diff --git a/magick/ImageMagick.h b/magick/ImageMagick.h
new file mode 100644
index 0000000..cc54f18
--- /dev/null
+++ b/magick/ImageMagick.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2009 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/magick/ImageMagick.ico b/magick/ImageMagick.ico
new file mode 100644
index 0000000..09def8c
--- /dev/null
+++ b/magick/ImageMagick.ico
Binary files differ
diff --git a/magick/ImageMagick.pc b/magick/ImageMagick.pc
new file mode 100644
index 0000000..72ce5d5
--- /dev/null
+++ b/magick/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.5.5
+Libs: -L${libdir} -lMagickCore
+Cflags: -I${includedir} -fopenmp
diff --git a/magick/ImageMagick.pc.in b/magick/ImageMagick.pc.in
new file mode 100644
index 0000000..f584ef5
--- /dev/null
+++ b/magick/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/magick/ImageMagick.rc b/magick/ImageMagick.rc
new file mode 100644
index 0000000..b1cfaf3
--- /dev/null
+++ b/magick/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/magick/Magick-config b/magick/Magick-config
new file mode 100755
index 0000000..9b859e0
--- /dev/null
+++ b/magick/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.5.5 Q16 '
+      ;;
+    --cflags)
+      echo "-I${includedir} -fopenmp"
+      ;;
+    --cxxflags)
+      echo '-g -O2 -Wall -W -pthread'
+      ;;
+    --cppflags)
+      echo '-I/usr/local/include/ImageMagick'
+      ;;
+    --ldflags)
+      echo '-L/usr/local/lib -lfreetype'
+      ;;
+    --libs)
+      echo "-L${libdir} -lMagickCore -llcms -ltiff -lfreetype -ljpeg -lfftw3 -lfontconfig -lXext -lSM -lICE -lX11 -lXt -lbz2 -lz -lm -lgomp -lpthread -lltdl"
+      ;;
+    *)
+      echo "${usage}" 1>&2
+      exit 1
+      ;;
+  esac
+  shift
+done
diff --git a/magick/Magick-config.1 b/magick/Magick-config.1
new file mode 100644
index 0000000..5c2bc2a
--- /dev/null
+++ b/magick/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/magick/Magick-config.in b/magick/Magick-config.in
new file mode 100644
index 0000000..8c08bf0
--- /dev/null
+++ b/magick/Magick-config.in
@@ -0,0 +1,63 @@
+#!/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: 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 '@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@"
+      ;;
+    *)
+      echo "${usage}" 1>&2
+      exit 1
+      ;;
+  esac
+  shift
+done
diff --git a/magick/MagickCore-config.1 b/magick/MagickCore-config.1
new file mode 100644
index 0000000..f58e957
--- /dev/null
+++ b/magick/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/magick/MagickCore-config.in b/magick/MagickCore-config.in
new file mode 100644
index 0000000..6020f8b
--- /dev/null
+++ b/magick/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/magick/MagickCore.h b/magick/MagickCore.h
new file mode 100644
index 0000000..618db2f
--- /dev/null
+++ b/magick/MagickCore.h
@@ -0,0 +1,229 @@
+/*
+  Copyright 1999-2009 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 "magick/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(__cplusplus) || defined(c_plusplus)
+#  undef inline
+# endif
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#if defined(__CYGWIN32__)
+#  if !defined(__CYGWIN__)
+#    define __CYGWIN__ __CYGWIN32__
+#  endif
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#  if !defined(__WINDOWS__)
+#    if defined(_WIN32)
+#      define __WINDOWS__ _WIN32
+#    else
+#      if defined(WIN32)
+#        define __WINDOWS__ WIN32
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined(_WIN64) || defined(WIN64)
+#  if !defined(__WINDOWS__)
+#    if defined(_WIN64)
+#      define __WINDOWS__ _WIN64
+#    else
+#      if !defined(WIN64)
+#        define __WINDOWS__ WIN64
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined(__WINDOWS__)
+# 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 "magick/methods.h"
+#endif
+#include "magick/magick-type.h"
+#include "magick/animate.h"
+#include "magick/annotate.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/cipher.h"
+#include "magick/client.h"
+#include "magick/coder.h"
+#include "magick/color.h"
+#include "magick/colorspace.h"
+#include "magick/compare.h"
+#include "magick/composite.h"
+#include "magick/compress.h"
+#include "magick/configure.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/delegate.h"
+#include "magick/deprecate.h"
+#include "magick/display.h"
+#include "magick/distort.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/fourier.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/hashmap.h"
+#include "magick/histogram.h"
+#include "magick/identify.h"
+#include "magick/image.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/matrix.h"
+#include "magick/memory_.h"
+#include "magick/module.h"
+#include "magick/mime.h"
+#include "magick/monitor.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/paint.h"
+#include "magick/pixel.h"
+#include "magick/policy.h"
+#include "magick/prepress.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/registry.h"
+#include "magick/random_.h"
+#include "magick/resample.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/segment.h"
+#include "magick/shear.h"
+#include "magick/signature.h"
+#include "magick/splay-tree.h"
+#include "magick/stream.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/timer.h"
+#include "magick/token.h"
+#include "magick/transform.h"
+#include "magick/threshold.h"
+#include "magick/type.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#include "magick/xml-tree.h"
+#include "magick/xwindow.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/MagickCore.pc.in b/magick/MagickCore.pc.in
new file mode 100644
index 0000000..6b062d7
--- /dev/null
+++ b/magick/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/magick/Make.com b/magick/Make.com
new file mode 100644
index 0000000..c13c1e4
--- /dev/null
+++ b/magick/Make.com
@@ -0,0 +1,173 @@
+$!
+$! 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 animate.c
+$call Make annotate.c
+$call Make artifact.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 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 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 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 option.c
+$call Make paint.c
+$call Make pixel.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 pixel-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 -
+  animate, annotate, artifact, blob, cache, cache-view, cipher, client, coder, -
+  color, colorspace, compare, composite, compress, configure, -
+  constitute, decorate, delegate, deprecate, display, distort, draw, -
+  effect, enhance, exception, fx, gem, geometry, hashmap, histogram, identify, -
+  image, layer, list, locale, log, magic, magick, matrix, memory, mime, -
+  module, monitor, montage, 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, prepress, property, xml-tree, -
+	[-.filters]analyze,[-.wand]drawing-wand, pixel-wand, pixel-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/magick/Makefile.am b/magick/Makefile.am
new file mode 100644
index 0000000..9bc4080
--- /dev/null
+++ b/magick/Makefile.am
@@ -0,0 +1,412 @@
+#  Copyright 1999-2009 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.
+#
+#  Copyright (C) 2003 - 2008 GraphicsMagick Group
+#
+#  Makefile for building the MagickCore API.
+# 
+
+magickincdir = $(topincludedir)/magick
+
+# Headers which are installed
+magickinc_HEADERS = \
+	$(MAGICK_INCLUDE_HDRS)
+
+MAGICK_BIN_SCRPTS = \
+  magick/Magick-config \
+  magick/MagickCore-config
+
+MAGICK_PKGCONFIG = \
+  magick/ImageMagick.pc \
+  magick/MagickCore.pc
+
+OSX_GCOV_LDFLAG = @OSX_GCOV_LDFLAG@
+
+MAGICK_MANS = \
+  magick/Magick-config.1 \
+  magick/MagickCore-config.1
+
+MAGICKCORE_LIBS = magick/libMagickCore.la
+
+if WITH_MODULES
+magick_libMagickCore_la_SOURCES = $(MAGICK_BASE_SRCS) $(MAGICK_PLATFORM_SRCS)
+magick_libMagickCore_la_LIBADD = $(MAGICK_DEP_LIBS) $(MAGICK_LIBLTDL)
+else
+magick_libMagickCore_la_SOURCES = $(MAGICK_BASE_SRCS) $(MAGICK_PLATFORM_SRCS) $(MAGICK_CODER_SRCS) $(MAGICK_FILTER_SRCS)
+magick_libMagickCore_la_LIBADD = $(MAGICK_DEP_LIBS) $(MAGICK_LIBLTDL)
+endif # WITH_MODULES
+magick_libMagickCore_la_CPPFLAGS = -I$(top_builddir)/ltdl -I$(top_srcdir)/ltdl $(LIBRARY_EXTRA_CPPFLAGS)
+magick_libMagickCore_la_LDFLAGS = -no-undefined -export-symbols-regex ".*" \
+  $(OSX_GCOV_LDFLAG) -version-info \
+  $(MAGICK_LIBRARY_CURRENT):$(MAGICK_LIBRARY_REVISION):$(MAGICK_LIBRARY_AGE)
+magick_libMagickCore_la_DEPENDENCIES = $(MAGICK_LTDLDEPS)
+
+# Library base sources
+MAGICK_BASE_SRCS = \
+	magick/ImageMagick.h \
+	magick/MagickCore.h \
+	magick/animate.c \
+	magick/animate.h \
+	magick/animate-private.h \
+	magick/annotate.c \
+	magick/annotate.h \
+	magick/api.h \
+	magick/artifact.c \
+	magick/artifact.h \
+	magick/blob.c \
+	magick/blob.h \
+	magick/blob-private.h \
+	magick/cache.c \
+	magick/cache.h \
+	magick/cache-private.h \
+	magick/cache-view.c \
+	magick/cache-view.h \
+	magick/cipher.c \
+	magick/cipher.h \
+	magick/client.c \
+	magick/client.h \
+	magick/coder.c \
+	magick/coder.h \
+	magick/color.c \
+	magick/color.h \
+	magick/color-private.h \
+	magick/colorspace.c \
+	magick/colorspace.h \
+	magick/colorspace-private.h \
+	magick/compare.c \
+	magick/compare.h \
+	magick/composite.c \
+	magick/composite.h \
+	magick/composite-private.h \
+	magick/compress.c \
+	magick/compress.h \
+	magick/configure.c \
+	magick/configure.h \
+	magick/constitute.c \
+	magick/constitute.h \
+	magick/decorate.c \
+	magick/decorate.h \
+	magick/delegate.c \
+	magick/delegate.h \
+	magick/delegate-private.h \
+	magick/deprecate.c \
+	magick/deprecate.h \
+	magick/display.c \
+	magick/display.h \
+	magick/display-private.h \
+	magick/distort.c \
+	magick/distort.h \
+	magick/draw.c \
+	magick/draw.h \
+	magick/draw-private.h \
+	magick/effect.c \
+	magick/effect.h \
+	magick/enhance.c \
+	magick/enhance.h \
+	magick/exception.c \
+	magick/exception.h \
+	magick/exception-private.h \
+	magick/fourier.c \
+	magick/fourier.h \
+	magick/fx.c \
+	magick/fx.h \
+	magick/fx-private.h \
+	magick/gem.c \
+	magick/gem.h \
+	magick/geometry.c \
+	magick/geometry.h \
+	magick/hashmap.c \
+	magick/hashmap.h \
+	magick/histogram.c \
+	magick/histogram.h \
+	magick/identify.c \
+	magick/identify.h \
+	magick/image.c \
+	magick/image.h \
+	magick/image-private.h \
+	magick/layer.c \
+	magick/layer.h \
+	magick/list.c \
+	magick/list.h \
+	magick/locale.c \
+	magick/locale_.h \
+	magick/log.c \
+	magick/log.h \
+	magick/mac.h \
+	magick/magic.c \
+	magick/magic.h \
+	magick/magick.c \
+	magick/magick-config.h \
+	magick/magick-type.h \
+	magick/magick.h \
+	magick/matrix.c \
+	magick/matrix.h \
+	magick/memory.c \
+	magick/memory_.h \
+	magick/methods.h \
+	magick/mime.c \
+	magick/mime.h \
+	magick/module.c \
+	magick/module.h \
+	magick/monitor.c \
+	magick/monitor.h \
+	magick/monitor-private.h \
+	magick/montage.c \
+	magick/montage.h \
+	magick/nt-base.h \
+	magick/nt-feature.h \
+	magick/option.c \
+	magick/option.h \
+	magick/paint.c \
+	magick/paint.h \
+	magick/pixel.c \
+	magick/pixel.h \
+	magick/pixel-private.h \
+	magick/policy.c \
+	magick/policy.h \
+	magick/PreRvIcccm.c \
+	magick/PreRvIcccm.h \
+	magick/prepress.c \
+	magick/prepress.h \
+	magick/property.c \
+	magick/property.h \
+	magick/profile.c \
+	magick/profile.h \
+	magick/quantize.c \
+	magick/quantize.h \
+	magick/quantum.c \
+	magick/quantum.h \
+	magick/quantum-export.c \
+	magick/quantum-import.c \
+	magick/quantum-private.h \
+	magick/random.c \
+	magick/random_.h \
+	magick/random-private.h \
+	magick/registry.c \
+	magick/registry.h \
+	magick/resample.c \
+	magick/resample.h \
+	magick/resample-private.h \
+	magick/resize.c \
+	magick/resize.h \
+	magick/resize-private.h \
+	magick/resource.c \
+	magick/resource_.h \
+	magick/segment.c \
+	magick/segment.h \
+	magick/semaphore.c \
+	magick/semaphore.h \
+	magick/shear.c \
+	magick/shear.h \
+	magick/signature.c \
+	magick/signature.h \
+	magick/signature-private.h \
+	magick/splay-tree.c \
+	magick/splay-tree.h \
+	magick/static.c \
+	magick/static.h \
+	magick/statistic.c \
+	magick/statistic.h \
+	magick/stream.c \
+	magick/stream.h \
+	magick/stream-private.h \
+	magick/string.c \
+	magick/string_.h \
+	magick/studio.h \
+	magick/thread.c \
+	magick/thread_.h \
+	magick/thread-private.h \
+	magick/timer.c \
+	magick/timer.h \
+	magick/token.c \
+	magick/token.h \
+	magick/token-private.h \
+	magick/transform.c \
+	magick/transform.h \
+	magick/threshold.c \
+	magick/threshold.h \
+	magick/type.c \
+	magick/type.h \
+	magick/utility.c \
+	magick/utility.h \
+	magick/version.c \
+	magick/version.h \
+	magick/vms.h \
+	magick/widget.c \
+	magick/widget.h \
+	magick/xml-tree.c \
+	magick/xml-tree.h \
+	magick/xwindow.c \
+	magick/xwindow.h 
+
+if WIN32_NATIVE_BUILD
+MAGICK_PLATFORM_SRCS = \
+	magick/nt-base.c \
+	magick/nt-base.h \
+	magick/nt-feature.c \
+	magick/nt-feature.h
+else
+if CYGWIN_BUILD
+MAGICK_PLATFORM_SRCS = \
+	magick/nt-feature.c \
+	magick/nt-feature.h
+else
+MAGICK_PLATFORM_SRCS =
+endif # if CYGWIN_BUILD
+endif # if WIN32_NATIVE_BUILD
+
+MAGICK_INCLUDE_HDRS = \
+	magick/ImageMagick.h \
+	magick/MagickCore.h \
+	magick/PreRvIcccm.h \
+	magick/animate.h \
+	magick/annotate.h \
+	magick/api.h \
+	magick/artifact.h \
+	magick/blob.h \
+	magick/cache.h \
+	magick/cache-view.h \
+	magick/cipher.h \
+	magick/client.h \
+	magick/coder.h \
+	magick/color.h \
+	magick/colorspace.h \
+	magick/compare.h \
+	magick/composite.h \
+	magick/compress.h \
+	magick/configure.h \
+	magick/constitute.h \
+	magick/decorate.h \
+	magick/delegate.h \
+	magick/deprecate.h \
+	magick/display.h \
+	magick/distort.h \
+	magick/draw.h \
+	magick/effect.h \
+	magick/enhance.h \
+	magick/exception.h \
+	magick/fourier.h \
+	magick/fx.h \
+	magick/gem.h \
+	magick/geometry.h \
+	magick/hashmap.h \
+	magick/histogram.h \
+	magick/identify.h \
+	magick/image.h \
+	magick/layer.h \
+	magick/list.h \
+	magick/locale_.h \
+	magick/log.h \
+	magick/magic.h \
+	magick/magick.h \
+	magick/magick-config.h \
+	magick/magick-type.h \
+	magick/matrix.h \
+	magick/memory_.h \
+	magick/methods.h \
+	magick/mime.h \
+	magick/module.h \
+	magick/monitor.h \
+	magick/montage.h \
+	magick/option.h \
+	magick/paint.h \
+	magick/pixel.h \
+	magick/policy.h \
+	magick/prepress.h \
+	magick/profile.h \
+	magick/property.h \
+	magick/quantize.h \
+	magick/quantum.h \
+	magick/random_.h \
+	magick/registry.h \
+	magick/resample.h \
+	magick/resize.h \
+	magick/resource_.h \
+	magick/segment.h \
+	magick/semaphore.h \
+	magick/shear.h \
+	magick/signature.h \
+	magick/splay-tree.h \
+	magick/statistic.h \
+	magick/stream.h \
+	magick/string_.h \
+	magick/timer.h \
+	magick/token.h \
+	magick/transform.h \
+	magick/threshold.h \
+	magick/type.h \
+	magick/utility.h \
+	magick/version.h \
+	magick/widget.h \
+	magick/xml-tree.h \
+	magick/xwindow.h
+
+MAGICK_NOINST_HDRS = \
+	magick/animate-private.h \
+	magick/blob-private.h \
+	magick/cache-private.h \
+	magick/color-private.h \
+	magick/colorspace-private.h \
+	magick/composite-private.h \
+	magick/delegate-private.h \
+	magick/display-private.h \
+	magick/draw-private.h \
+	magick/exception-private.h \
+	magick/fx-private.h \
+	magick/image-private.h \
+	magick/mac.h \
+	magick/mime-private.h \
+	magick/monitor-private.h \
+	magick/nt-base.h \
+	magick/nt-feature.h \
+	magick/pixel-private.h \
+	magick/quantum-private.h \
+	magick/random-private.h \
+	magick/resample-private.h \
+	magick/resize-private.h \
+	magick/signature-private.h \
+	magick/static.h \
+	magick/stream-private.h \
+	magick/studio.h \
+	magick/thread_.h \
+	magick/thread-private.h \
+	magick/token-private.h \
+	magick/xwindow-private.h \
+	magick/vms.h
+
+MAGICK_EXTRA_DIST = \
+	magick/Magick-config.in \
+	magick/MagickCore-config.in \
+	$(MAGICK_MANS) \
+	magick/ImageMagick.pc.in \
+	magick/MagickCore.pc.in \
+	magick/Make.com \
+	magick/config.h_vms \
+	magick/mac.c \
+	magick/nt-base.c \
+	magick/nt-feature.c \
+	magick/vms.c \
+	magick/xwdfile.h_vms 
+
+# Install magick-config.h
+MAGICK_INSTALL_DATA_LOCAL_TARGETS = magick-install-data-local
+magick-install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(magickincdir)
+	$(INSTALL_HEADER) magick/magick-config.h $(DESTDIR)$(magickincdir)/magick-config.h
+
+# Uninstall magick-config.h
+MAGICK_UNINSTALL_LOCAL_TARGETS = magick-uninstall-local
+magick-uninstall-local:
+	rm -f $(DESTDIR)$(magickincdir)/magick-config.h
+
diff --git a/magick/PreRvIcccm.c b/magick/PreRvIcccm.c
new file mode 100644
index 0000000..7bce9cc
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#if defined(MAGICKCORE_X11_DELEGATE)
+#include "magick/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,unsigned long 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;
+
+  unsigned long
+    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 < (long) 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 < (long) 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/magick/PreRvIcccm.h b/magick/PreRvIcccm.h
new file mode 100644
index 0000000..0c2b4df
--- /dev/null
+++ b/magick/PreRvIcccm.h
@@ -0,0 +1,115 @@
+/*
+  Copyright 1999-2009 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;
+
+  unsigned long
+    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/magick/animate-private.h b/magick/animate-private.h
new file mode 100644
index 0000000..67ccb5c
--- /dev/null
+++ b/magick/animate-private.h
@@ -0,0 +1,39 @@
+/*
+  Copyright 1999-2009 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 "magick/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/magick/animate.c b/magick/animate.c
new file mode 100644
index 0000000..850eba3
--- /dev/null
+++ b/magick/animate.c
@@ -0,0 +1,3031 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                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-2009 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 "magick/studio.h"
+#include "magick/animate.h"
+#include "magick/animate-private.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/property.h"
+#include "magick/resource_.h"
+#include "magick/string_.h"
+#include "magick/transform.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#include "magick/widget.h"
+#include "magick/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) FormatMagickString(windows->image.name,MaxTextExtent,
+        "ImageMagick: %s",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) FormatMagickString(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((unsigned long *) 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 long MagickMax(const long x,const long 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 long
+    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;
+
+  unsigned long
+    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) FormatMagickString(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 > (unsigned long) visual_info->colormap_size))
+            break;
+          for (i=0; i < (long) images->colors; i++)
+            if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
+              break;
+          if (i < (long) 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 < (long) number_scenes; i++)
+    if (image_list[i]->scene == 0)
+      break;
+  if (i == (long) 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) FormatMagickString(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=window_info.x;
+  geometry_info.y=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[%lu] %lux%lu ",image_list[0]->filename,
+        image_list[0]->scene,image_list[0]->columns,image_list[0]->rows);
+      if (image_list[0]->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
+          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) FormatMagickString(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)
+        XGetPixelPacket(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: [%lu] %s %ux%u ",image_list[scene]->scene,
+          image_list[scene]->filename,columns,rows);
+        if (image_list[scene]->colors != 0)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
+            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],
+    *cwd,
+    geometry[MaxTextExtent],
+    resource_name[MaxTextExtent];
+
+  CommandType
+    command_type;
+
+  Image
+    *coalesce_image,
+    *display_image,
+    *image,
+    **image_list,
+    *nexus;
+
+  int
+    status;
+
+  long
+    first_scene,
+    iterations,
+    scene;
+
+  KeySym
+    key_symbol;
+
+  MagickStatusType
+    context_mask,
+    state;
+
+  RectangleInfo
+    geometry_info;
+
+  register char
+    *p;
+
+  register long
+    i;
+
+  static char
+    working_directory[MaxTextExtent];
+
+  static unsigned long
+    number_windows;
+
+  static XWindowInfo
+    *magick_windows[MaXWindows];
+
+  time_t
+    timestamp;
+
+  unsigned long
+    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 < (long) 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 > (unsigned long) visual_info->colormap_size))
+            break;
+          for (i=0; i < (long) images->colors; i++)
+            if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
+              break;
+          if (i < (long) 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 < (long) number_scenes; scene++)
+    if (image_list[scene]->scene == 0)
+      break;
+  if (scene == (long) 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 < (long) 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[%lu] %lux%lu ",display_image->filename,
+        display_image->scene,display_image->columns,display_image->rows);
+      if (display_image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
+          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,
+    (unsigned long) (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,
+    (unsigned long) (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) FormatMagickString(windows->image.name,MaxTextExtent,
+        "ImageMagick: %s[%lu of %lu]",filename,display_image->scene,
+        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) FormatMagickString(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=(unsigned long) (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) FormatMagickString(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) FormatMagickString(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);
+  if ((windows->image.mapped == MagickFalse) ||
+      (windows->backdrop.id != (Window) NULL))
+    (void) XMapWindow(display,windows->image.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;
+  status=XMakeImage(display,resource_info,&windows->image,display_image,
+    (unsigned int) display_image->columns,(unsigned int) display_image->rows);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      images->filename);
+  if (windows->image.mapped)
+    XRefreshWindow(display,&windows->image,(XEvent *) NULL);
+  /*
+    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);
+  (void) XMapWindow(display,windows->image.id);
+  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);
+  windows->image.pixmaps[0]=windows->image.pixmap;
+  windows->image.matte_pixmaps[0]=windows->image.matte_pixmap;
+  for (scene=1; scene < (long) 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)
+        XGetPixelPacket(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: [%lu] %s %ux%u ",image_list[scene]->scene,
+          image_list[scene]->filename,columns,rows);
+        if (image_list[scene]->colors != 0)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
+            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) FormatMagickString(windows->image.name,MaxTextExtent,
+          "ImageMagick: %s[%lu of %lu]",p,scene+1,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;
+    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);
+    delay=1000*image_list[scene]->delay/MagickMax(images->ticks_per_second,1L);
+    XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
+    if (XCheckTypedWindowEvent(display,windows->image.id,KeyPress,&event) != 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;
+          }
+      }
+  }
+  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 < ((long) number_scenes-1))
+                scene++;
+              else
+                {
+                  iterations++;
+                  if (iterations == (long) image_list[0]->iterations)
+                    {
+                      iterations=0;
+                      state|=ExitState;
+                    }
+                  if (state & AutoReverseAnimationState)
+                    {
+                      state&=(~ForwardAnimationState);
+                      scene--;
+                    }
+                  else
+                    {
+                      if ((state & RepeatAnimationState) == MagickFalse)
+                        state&=(~PlayAnimationState);
+                      scene=first_scene;
+                      pause=MagickTrue;
+                    }
+                }
+            }
+          else
+            {
+              /*
+                Reverse animation:  decrement scene number.
+              */
+              if (scene > first_scene)
+                scene--;
+              else
+                {
+                  iterations++;
+                  if (iterations == (long) 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=(long) 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) FormatMagickString(windows->image.name,MaxTextExtent,
+                "ImageMagick: %s[%lu of %lu]",p,scene+1,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.
+          */
+          XGetPixelPacket(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;
+          XRefreshWindow(display,&windows->image,&event);
+          (void) XSync(display,MagickFalse);
+          state&=(~StepAnimationState);
+          if (pause != MagickFalse)
+            for (i=0; i < (long) 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",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_colormap)
+              {
+                /*
+                  Update graphic context and window colormap.
+                */
+                for (i=0; i < (long) 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,
+                    (unsigned long) (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,
+                    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",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;
+        (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 < (long) 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;
+  }
+  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.
+  */
+  cwd=getcwd(working_directory,MaxTextExtent);
+  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,MagickFalse,&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) FormatMagickString(quality,MaxTextExtent,"%lu",
+        image_info->quality);
+      status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
+        quality);
+      if (*quality == '\0')
+        return(MagickTrue);
+      image->quality=(unsigned long) atol(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) FormatMagickString(geometry,MaxTextExtent,PSPageGeometry);
+      if (LocaleCompare(image_info->magick,"PDF") == 0)
+        (void) FormatMagickString(geometry,MaxTextExtent,PSPageGeometry);
+      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/magick/animate.h b/magick/animate.h
new file mode 100644
index 0000000..9f007c0
--- /dev/null
+++ b/magick/animate.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2009 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/magick/annotate.c b/magick/annotate.c
new file mode 100644
index 0000000..bb0933e
--- /dev/null
+++ b/magick/annotate.c
@@ -0,0 +1,1950 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/annotate.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/draw-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/log.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/property.h"
+#include "magick/resource_.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/token-private.h"
+#include "magick/transform.h"
+#include "magick/type.h"
+#include "magick/utility.h"
+#include "magick/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
+
+/*
+  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 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 long
+    i;
+
+  size_t
+    length;
+
+  TypeMetric
+    metrics;
+
+  unsigned long
+    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=(unsigned long) 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=(unsigned long) (metrics.ascent-metrics.descent+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.opacity != TransparentOpacity)
+      {
+        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) FormatMagickString(primitive,MaxTextExtent,
+          "rectangle 0,0 %g,%ld",metrics.origin.x,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) FormatMagickString(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:
+%
+%      long FormatMagickCaption(Image *image,DrawInfo *draw_info,
+%        TypeMetric *metrics,char **caption)
+%
+%  A description of each parameter follows.
+%
+%    o image:  The image.
+%
+%    o caption: the caption.
+%
+%    o draw_info: the draw info.
+%
+%    o metrics: Return the font metrics in this structure.
+%
+*/
+MagickExport long FormatMagickCaption(Image *image,DrawInfo *draw_info,
+  TypeMetric *metrics,char **caption)
+{
+  MagickBooleanType
+    status;
+
+  register char
+    *p,
+    *q,
+    *s;
+
+  register long
+    i;
+
+  unsigned long
+    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 < (long) GetUTFOctets(p); i++)
+      *q++=(*(p+i));
+    *q='\0';
+    status=GetTypeMetrics(image,draw_info,metrics);
+    if (status == MagickFalse)
+      break;
+    width=(unsigned long) (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
+      {
+        char
+          *target;
+
+        long
+          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 long
+    i;
+
+  TypeMetric
+    extent;
+
+  unsigned long
+    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->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;
+  (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;
+  }
+  number_lines=(unsigned long) i;
+  metrics->height=(double) number_lines*(long) (metrics->ascent-
+    metrics->descent+0.5);
+  /*
+    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;
+  (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((const char *) NULL,draw_info->style,
+      draw_info->stretch,draw_info->weight,&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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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;
+
+  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;
+
+  long
+    code,
+    y;
+
+  PointInfo
+    point,
+    resolution;
+
+  register char
+    *p;
+
+  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
+    };
+
+  /*
+    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,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 (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);
+    }
+  point.x=0.0;
+  point.y=0.0;
+  code=0;
+  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
+  {
+    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*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+=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.opacity != TransparentOpacity) ||
+          (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 < (long) bitmap->bitmap.rows; y++)
+        {
+          long
+            x_offset,
+            y_offset;
+
+          MagickBooleanType
+            active,
+            sync;
+
+          MagickRealType
+            fill_opacity;
+
+          PixelPacket
+            fill_color;
+
+          register long
+            x;
+
+          register PixelPacket
+            *__restrict q;
+
+          register unsigned char
+            *p;
+
+          if (status == MagickFalse)
+            continue;
+          x_offset=(long) (point.x+0.5);
+          y_offset=(long) (point.y+y+0.5);
+          if ((y_offset < 0) || (y_offset >= (long) image->rows))
+            continue;
+          q=(PixelPacket *) NULL;
+          if ((x_offset < 0) || (x_offset >= (long) image->columns))
+            active=MagickFalse;
+          else
+            {
+              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
+                bitmap->bitmap.width,1,exception);
+              active=q != (PixelPacket *) NULL ? MagickTrue : MagickFalse;
+            }
+          p=bitmap->bitmap.buffer+y*bitmap->bitmap.width;
+          for (x=0; x < (long) bitmap->bitmap.width; x++)
+          {
+            x_offset++;
+            if ((*p == 0) || (x_offset < 0) ||
+                (x_offset >= (long) image->columns))
+              {
+                p++;
+                q++;
+                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 == (PixelPacket *) NULL)
+              {
+                p++;
+                q++;
+                continue;
+              }
+            (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color);
+            fill_opacity=QuantumRange-fill_opacity*(QuantumRange-
+              fill_color.opacity);
+            MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q);
+            if (active == MagickFalse)
+              {
+                sync=SyncCacheViewAuthenticPixels(image_view,exception);
+                if (sync == MagickFalse)
+                  status=MagickFalse;
+              }
+            p++;
+            q++;
+          }
+          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*draw_info->interword_spacing;
+    else
+      origin.x+=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 (last_glyph.id != 0)
+    FT_Done_Glyph(last_glyph.image);
+  if ((draw_info->stroke.opacity != TransparentOpacity) ||
+      (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);
+  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 long
+    i;
+
+  size_t
+    escapes;
+
+  escapes=0;
+  buffer=AcquireString(text);
+  p=buffer;
+  for (i=0; i < (long) 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;
+
+  long
+    y;
+
+  MagickBooleanType
+    identity;
+
+  PointInfo
+    extent,
+    point,
+    resolution;
+
+  register long
+    i;
+
+  /*
+    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) fprintf(file,"%%!PS-Adobe-3.0\n");
+  (void) fprintf(file,"/ReencodeType\n");
+  (void) fprintf(file,"{\n");
+  (void) fprintf(file,"  findfont dup length\n");
+  (void) fprintf(file,
+    "  dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
+  (void) fprintf(file,
+    "  /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
+  (void) fprintf(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 <= (long) (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) fprintf(file,"%g %g moveto\n",identity  != MagickFalse ? 0.0 :
+    extent.x/2.0,extent.y/2.0);
+  (void) fprintf(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) fprintf(file,
+      "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
+  else
+    (void) fprintf(file,"/%s-ISO dup /%s ReencodeType findfont setfont\n",
+      draw_info->font,draw_info->font);
+  (void) fprintf(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) fprintf(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",text);
+  (void) fprintf(file,"(%s) show\n",text);
+  text=DestroyString(text);
+  (void) fprintf(file,"showpage\n");
+  (void) fclose(file);
+  (void) FormatMagickString(geometry,MaxTextExtent,"%ldx%ld+0+0!",(long)
+    (extent.x+0.5),(long) (extent.y+0.5));
+  annotate_info=AcquireImageInfo();
+  (void) FormatMagickString(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=(unsigned long) ((resolution.y/DefaultResolution)*
+        ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
+      crop_info.y=(long) ((resolution.y/DefaultResolution)*extent.y/8.0+0.5);
+      (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
+        crop_info.width,crop_info.height,crop_info.x,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.opacity != TransparentOpacity)
+    {
+      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 < (long) annotate_image->rows; y++)
+      {
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
+          1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        for (x=0; x < (long) annotate_image->columns; x++)
+        {
+          (void) GetFillColor(draw_info,x,y,&fill_color);
+          q->opacity=RoundToQuantum(QuantumRange-(((QuantumRange-
+            (MagickRealType) PixelIntensityToQuantum(q))*(QuantumRange-
+            fill_color.opacity))/QuantumRange));
+          q->red=fill_color.red;
+          q->green=fill_color.green;
+          q->blue=fill_color.blue;
+          q++;
+        }
+        sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      annotate_view=DestroyCacheView(annotate_view);
+      (void) CompositeImage(image,OverCompositeOp,annotate_image,
+        (long) (offset->x+0.5),(long) (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;
+
+  unsigned long
+    height,
+    width;
+
+  if (display == (Display *) NULL)
+    {
+      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();
+      resource_database=XGetResourceDatabase(display,GetClientName());
+      XGetResourceInfo(image_info,resource_database,GetClientName(),
+        &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);
+      XGetPixelPacket(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);
+    }
+  /*
+    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.opacity == TransparentOpacity)
+    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) FormatMagickString(annotate_info.geometry,MaxTextExtent,
+    "%lux%lu+%ld+%ld",width,height,(long) (offset->x+0.5),
+    (long) (offset->y-metrics->ascent-metrics->descent+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/magick/annotate.h b/magick/annotate.h
new file mode 100644
index 0000000..d7db220
--- /dev/null
+++ b/magick/annotate.h
@@ -0,0 +1,39 @@
+/*
+  Copyright 1999-2009 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 "magick/draw.h"
+
+extern MagickExport long
+  FormatMagickCaption(Image *,DrawInfo *,TypeMetric *,char **);
+
+extern MagickExport MagickBooleanType
+  AnnotateImage(Image *,const DrawInfo *),
+  GetMultilineTypeMetrics(Image *,const DrawInfo *,TypeMetric *),
+  GetTypeMetrics(Image *,const DrawInfo *,TypeMetric *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/api.h b/magick/api.h
new file mode 100644
index 0000000..c3f3dc3
--- /dev/null
+++ b/magick/api.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2009 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/magick/artifact.c b/magick/artifact.c
new file mode 100644
index 0000000..0b0f5f4
--- /dev/null
+++ b/magick/artifact.c
@@ -0,0 +1,448 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/compare.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/fx-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/profile.h"
+#include "magick/quantum.h"
+#include "magick/resource_.h"
+#include "magick/splay-tree.h"
+#include "magick/signature-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/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.
+%
+%  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/magick/artifact.h b/magick/artifact.h
new file mode 100644
index 0000000..b8d8ac2
--- /dev/null
+++ b/magick/artifact.h
@@ -0,0 +1,46 @@
+/*
+  Copyright 1999-2009 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/magick/blob-private.h b/magick/blob-private.h
new file mode 100644
index 0000000..64bf419
--- /dev/null
+++ b/magick/blob-private.h
@@ -0,0 +1,126 @@
+/*
+  Copyright 1999-2009 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 "magick/image.h"
+#include "magick/stream.h"
+
+#define MagickMinBlobExtent  32767L
+
+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 *),
+  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 *);
+
+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),
+  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/magick/blob.c b/magick/blob.c
new file mode 100644
index 0000000..9fd4baf
--- /dev/null
+++ b/magick/blob.c
@@ -0,0 +1,4268 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                         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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/client.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/policy.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#if defined(MAGICKCORE_HAVE_MMAP_FILEIO) && !defined(__WINDOWS__)
+# 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(MAGICKCORE_HAVE_FSEEKO)
+# define fseek  fseeko
+# define ftell  ftello
+#endif
+#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;
+
+  long
+    reference_count;
+
+  unsigned long
+    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 size_t MagickMin(const size_t x,const size_t 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,MagickMin(length-i,(size_t)
+      SSIZE_MAX));
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+  }
+  file=close(file)-1;
+  if (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,MagickFalse,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) FormatMagickString(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->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=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:
+    case BlobStream:
+      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;
+  (void) LockSemaphoreInfo(image->blob->semaphore);
+  image->blob->reference_count--;
+  assert(image->blob->reference_count >= 0);
+  if (image->blob->reference_count == 0)
+    destroy=MagickTrue;
+  (void) 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 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 blob.  It returns the
+%  file as a blob and its length.  If an error occurs, NULL is returned.
+%
+%  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) MagickSeek(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=MagickMin((size_t) 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;
+      }
+      file=close(file)-1;
+      if (blob == (unsigned char *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+          return((unsigned char *) NULL);
+        }
+      *length=MagickMin(i+count,extent);
+      blob[*length]='\0';
+      return(blob);
+    }
+  *length=MagickMin((size_t) offset,extent);
+  blob=(unsigned char *) NULL;
+  if (~(*length) >= MaxTextExtent)
+    blob=(unsigned char *) AcquireQuantumMemory(*length+MaxTextExtent,
+      sizeof(*blob));
+  if (blob == (unsigned char *) NULL)
+    {
+      file=close(file)-1;
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+      return((unsigned char *) NULL);
+    }
+  map=MapBlob(file,ReadMode,0,*length);
+  if (map != (unsigned char *) NULL)
+    {
+      (void) CopyMagickMemory(blob,map,*length);
+      (void) UnmapBlob(map,*length);
+    }
+  else
+    {
+      (void) MagickSeek(file,0,SEEK_SET);
+      for (i=0; i < *length; i+=count)
+      {
+        count=(ssize_t) read(file,blob+i,MagickMin(*length-i,(size_t)
+          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);
+        }
+    }
+  file=close(file)-1;
+  blob[*length]='\0';
+  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) CopyMagickMemory(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=MagickMin((size_t) 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)-1;
+  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
+    length;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  length=0;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+    {
+      length=image->blob->size;
+      break;
+    }
+    case FileStream:
+    {
+      if (fstat(fileno(image->blob->file),&image->blob->properties) == 0)
+        length=(MagickSizeType) image->blob->properties.st_size;
+      break;
+    }
+    case StandardStream:
+    case PipeStream:
+    {
+      length=image->blob->size;
+      break;
+    }
+    case ZipStream:
+    case BZipStream:
+    {
+      MagickBooleanType
+        status;
+
+      status=GetPathAttributes(image->filename,&image->blob->properties);
+      if (status != MagickFalse)
+        length=(MagickSizeType) image->blob->properties.st_size;
+      break;
+    }
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+      length=(MagickSizeType) image->blob->length;
+      break;
+    }
+  }
+  return(length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 blob and its length.  The magick member of the ImageInfo structure
+%  determines the format of the returned blob (GIF, JPEG,  PNG, etc.)
+%
+%  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,MagickTrue,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) FormatMagickString(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.
+%
+*/
+
+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,(size_t) (image->blob->length-
+    image->blob->offset));
+  image->blob->offset+=(*count);
+  if (*count != (ssize_t) length)
+    image->blob->eof=MagickTrue;
+  return(data);
+}
+
+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=MagickMin((size_t) 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;
+  }
+  file=close(file)-1;
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  if (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,MagickTrue,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) FormatMagickString(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 long
+    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) FormatMagickString(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=MagickMin((size_t) 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)-1;
+  (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);
+      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
+    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)
+    {
+      (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(__WINDOWS__) || 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(atoi(filename+3),mode);
+#if defined(__WINDOWS__) || 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
+  if (*type == 'w')
+    {
+      /*
+        Form filename for multi-part images.
+      */
+      (void) InterpretImageFilename(image_info,image,image->filename,(int)
+        image->scene,filename);
+      if (image_info->adjoin == MagickFalse)
+        if ((image->previous != (Image *) NULL) ||
+            (GetNextImageInList(image) != (Image *) NULL))
+          {
+            if (LocaleCompare(filename,image->filename) == 0)
+              {
+                char
+                  extension[MaxTextExtent],
+                  path[MaxTextExtent];
+
+                GetPathComponent(image->filename,RootPath,path);
+                GetPathComponent(image->filename,ExtensionPath,extension);
+                if (*extension == '\0')
+                  (void) FormatMagickString(filename,MaxTextExtent,"%s-%lu",
+                    path,image->scene);
+                else
+                  (void) FormatMagickString(filename,MaxTextExtent,"%s-%lu.%s",
+                    path,image->scene,extension);
+              }
+          }
+      (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+#if defined(macintosh)
+      SetApplicationType(filename,image_info->magick,'8BIM');
+#endif
+    }
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+  if (((strlen(filename) > 2) &&
+       (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
+      ((strlen(filename) > 3) &&
+       (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
+      ((strlen(filename) > 4) &&
+       (LocaleCompare(filename+strlen(filename)-4,".wmz") == 0)) ||
+      ((strlen(filename) > 5) &&
+       (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0)))
+    {
+      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 ((strlen(filename) > 4) &&
+        (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
+      {
+        image->blob->file=(FILE *) BZ2_bzopen(filename,type);
+        if (image->blob->file != (FILE *) NULL)
+          image->blob->type=BZipStream;
+      }
+    else
+#endif
+      if (image_info->file != (FILE *) NULL)
+        {
+          image->blob->file=image_info->file;
+          image->blob->type=FileStream;
+          image->blob->exempt=MagickTrue;
+        }
+      else
+        {
+          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
+              if (*type == 'r')
+                {
+                  size_t
+                    count;
+
+                  unsigned char
+                    magick[3];
+
+                  (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 %ld magic header bytes",(long) 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) && (*type == 'r'))
+      {
+        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;
+              }
+          }
+      }
+  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) CopyMagickMemory(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,(size_t) (image->blob->length-
+        image->blob->offset));
+      image->blob->offset+=count;
+      if (count != (ssize_t) length)
+        image->blob->eof=MagickTrue;
+      (void) CopyMagickMemory(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 long 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 value as a 64-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobLong method is:
+%
+%      MagickSizeType ReadBlobLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickSizeType ReadBlobLongLong(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[8];
+
+  MagickSizeType
+    value;
+
+  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 long 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 long 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 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 long
+    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] == '\n') || (string[i] == '\r'))
+      break;
+  }
+  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(),"...");
+  (void) LockSemaphoreInfo(blob->semaphore);
+  blob->reference_count++;
+  (void) 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) CopyMagickMemory(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 long 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 long 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 long 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 long 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 S h o r t                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobMSBShort() writes a long 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/magick/blob.h b/magick/blob.h
new file mode 100644
index 0000000..a2a4f57
--- /dev/null
+++ b/magick/blob.h
@@ -0,0 +1,76 @@
+/*
+  Copyright 1999-2009 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 "magick/image.h"
+#include "magick/stream.h"
+
+#define MagickMaxBufferExtent  0x3c005L
+
+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/magick/cache-private.h b/magick/cache-private.h
new file mode 100644
index 0000000..3ce2934
--- /dev/null
+++ b/magick/cache-private.h
@@ -0,0 +1,239 @@
+/*
+  Copyright 1999-2009 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 "magick/random_.h"
+#include "magick/thread-private.h"
+#include "magick/semaphore.h"
+
+typedef enum
+{
+  UndefinedCache,
+  MemoryCache,
+  MapCache,
+  DiskCache
+} CacheType;
+
+typedef void
+  *Cache;
+
+typedef const IndexPacket
+  *(*GetVirtualIndexesFromHandler)(const Image *);
+
+typedef IndexPacket
+  *(*GetAuthenticIndexesFromHandler)(const Image *);
+
+typedef MagickBooleanType
+  (*GetOneAuthenticPixelFromHandler)(Image *,const long,const long,
+    PixelPacket *,ExceptionInfo *),
+  (*GetOneVirtualPixelFromHandler)(const Image *,const VirtualPixelMethod,
+    const long,const long,PixelPacket *,ExceptionInfo *),
+  (*SyncAuthenticPixelsHandler)(Image *,ExceptionInfo *);
+
+typedef const PixelPacket
+  *(*GetVirtualPixelHandler)(const Image *,const VirtualPixelMethod,const long,
+    const long,const unsigned long,const unsigned long,ExceptionInfo *),
+  *(*GetVirtualPixelsHandler)(const Image *);
+
+typedef PixelPacket
+  *(*GetAuthenticPixelsHandler)(Image *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *);
+
+typedef PixelPacket
+  *(*GetAuthenticPixelsFromHandler)(const Image *);
+
+typedef PixelPacket
+  *(*QueueAuthenticPixelsHandler)(Image *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *);
+
+typedef void
+  (*DestroyPixelHandler)(Image *);
+
+typedef struct _CacheMethods
+{
+  GetVirtualPixelHandler
+    get_virtual_pixel_handler;
+
+  GetVirtualPixelsHandler
+    get_virtual_pixels_handler;
+
+  GetVirtualIndexesFromHandler
+    get_virtual_indexes_from_handler;
+
+  GetOneVirtualPixelFromHandler
+    get_one_virtual_pixel_from_handler;
+
+  GetAuthenticPixelsHandler
+    get_authentic_pixels_handler;
+
+  GetAuthenticIndexesFromHandler
+    get_authentic_indexes_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;
+
+  CacheType
+    type;
+
+  MagickBooleanType
+    mapped;
+
+  unsigned long
+    columns,
+    rows;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    length;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  unsigned long
+    number_threads;
+
+  NexusInfo
+    **nexus_info;
+
+  PixelPacket
+    *pixels;
+
+  IndexPacket
+    *indexes;
+
+  MagickBooleanType
+    active_index_channel;
+
+  int
+    file;
+
+  char
+    filename[MaxTextExtent],
+    cache_filename[MaxTextExtent];
+
+  CacheMethods
+    methods;
+
+  RandomInfo
+    *random_info;
+
+  MagickBooleanType
+    debug;
+
+  MagickThreadType
+    id;
+
+  long
+    reference_count;
+
+  SemaphoreInfo
+    *semaphore,
+    *disk_semaphore;
+
+  time_t
+    timestamp;
+
+  unsigned long
+    signature;
+} CacheInfo;
+
+extern MagickExport Cache
+  AcquirePixelCache(const unsigned long),
+  ClonePixelCache(const Cache),
+  DestroyPixelCache(Cache),
+  GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *),
+  ReferencePixelCache(Cache);
+
+extern MagickExport ClassType
+  GetPixelCacheStorageClass(const Cache);
+
+extern MagickExport ColorspaceType
+  GetPixelCacheColorspace(const Cache);
+
+extern MagickExport const IndexPacket
+  *GetVirtualIndexesFromNexus(const Cache,NexusInfo *);
+
+extern MagickExport const PixelPacket
+  *GetVirtualPixelsFromNexus(const Image *,const VirtualPixelMethod,const long,
+    const long,const unsigned long,const unsigned long,NexusInfo *,
+    ExceptionInfo *),
+  *GetVirtualPixelsNexus(const Cache,NexusInfo *);
+
+extern MagickExport IndexPacket
+  *GetPixelCacheNexusIndexes(const Cache,NexusInfo *);
+
+extern MagickExport MagickBooleanType
+  SyncAuthenticPixelCacheNexus(Image *,NexusInfo *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetPixelCacheNexusExtent(const Cache,NexusInfo *);
+
+extern MagickExport NexusInfo
+  **AcquirePixelCacheNexus(const unsigned long),
+  **DestroyPixelCacheNexus(NexusInfo **,const unsigned long);
+
+extern MagickExport PixelPacket
+  *GetAuthenticPixelCacheNexus(Image *,const long,const long,
+    const unsigned long,const unsigned long,NexusInfo *,ExceptionInfo *),
+  *GetPixelCacheNexusPixels(const Cache,NexusInfo *),
+  *QueueAuthenticNexus(Image *,const long,const long,const unsigned long,
+    const unsigned long,NexusInfo *,ExceptionInfo *);
+
+extern MagickExport void
+  ClonePixelCacheMethods(Cache,const Cache),
+  GetPixelCacheMethods(CacheMethods *),
+  SetPixelCacheMethods(Cache,CacheMethods *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/cache-view.c b/magick/cache-view.c
new file mode 100644
index 0000000..20adb04
--- /dev/null
+++ b/magick/cache-view.c
@@ -0,0 +1,1021 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/cache-view.h"
+#include "magick/memory_.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+
+/*
+  Typedef declarations.
+*/
+struct _CacheView
+{
+  Image
+    *image;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  unsigned long
+    number_threads;
+
+  NexusInfo
+    **nexus_info;
+
+  MagickBooleanType
+    debug;
+
+  unsigned long
+    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 *) AcquireAlignedMemory(1,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 *) AcquireAlignedMemory(1,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 *) RelinquishAlignedMemory(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(cache_view->image->colorspace);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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)
+{
+  long
+    id;
+
+  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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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(cache_view->image->storage_class);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      PixelPacket *GetCacheViewAuthenticPixels(CacheView *cache_view,
+%        const long x,const long y,const unsigned long columns,
+%        const unsigned long 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 PixelPacket *GetCacheViewAuthenticPixels(CacheView *cache_view,
+  const long x,const long y,const unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+  Cache
+    cache;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  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=GetImagePixelCache(cache_view->image,MagickTrue,exception);
+  if (cache == (Cache) NULL)
+    return((PixelPacket *) NULL);
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  pixels=GetAuthenticPixelCacheNexus(cache_view->image,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 long x,const long 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 long x,const long y,PixelPacket *pixel,
+  ExceptionInfo *exception)
+{
+  Cache
+    cache;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  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=GetImagePixelCache(cache_view->image,MagickTrue,exception);
+  if (cache == (Cache) NULL)
+    return(MagickFalse);
+  *pixel=cache_view->image->background_color;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  pixels=GetAuthenticPixelCacheNexus(cache_view->image,x,y,1,1,
+    cache_view->nexus_info[id],exception);
+  if (pixels == (const PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w A u t h e n t i c I n d e x Q u e u e             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewAuthenticIndexQueue() returns the indexes associated with the
+%  last call to SetCacheViewIndexes() or GetCacheViewAuthenticIndexQueue().  The
+%  indexes are authentic and can be updated.
+%
+%  The format of the GetCacheViewAuthenticIndexQueue() method is:
+%
+%      IndexPacket *GetCacheViewAuthenticIndexQueue(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport IndexPacket *GetCacheViewAuthenticIndexQueue(CacheView *cache_view)
+{
+  IndexPacket
+    *indexes;
+
+  long
+    id;
+
+  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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  indexes=GetPixelCacheNexusIndexes(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      PixelPacket *GetCacheViewAuthenticPixelQueue(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport PixelPacket *GetCacheViewAuthenticPixelQueue(CacheView *cache_view)
+{
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 I n d e x Q u e u e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewVirtualIndexQueue() returns the indexes associated with the
+%  last call to GetCacheViewVirtualIndexQueue().  The indexes are virtual and
+%  therefore cannot be updated.
+%
+%  The format of the GetCacheViewVirtualIndexQueue() method is:
+%
+%      const IndexPacket *GetCacheViewVirtualIndexQueue(
+%        const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport const IndexPacket *GetCacheViewVirtualIndexQueue(
+  const CacheView *cache_view)
+{
+  const IndexPacket
+    *indexes;
+
+  long
+    id;
+
+  assert(cache_view != (const 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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  indexes=GetVirtualIndexesFromNexus(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 PixelPacket *GetCacheViewVirtualPixelQueue(
+%        const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport const PixelPacket *GetCacheViewVirtualPixelQueue(
+  const CacheView *cache_view)
+{
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  assert(cache_view != (const 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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 PixelPacket *GetCacheViewVirtualPixels(
+%        const CacheView *cache_view,const long x,const long y,
+%        const unsigned long columns,const unsigned long 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 PixelPacket *GetCacheViewVirtualPixels(
+  const CacheView *cache_view,const long x,const long y,
+  const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
+{
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 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 long x,const long 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 long x,const long y,PixelPacket *pixel,
+  ExceptionInfo *exception)
+{
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  *pixel=cache_view->image->background_color;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  pixels=GetVirtualPixelsFromNexus(cache_view->image,
+    cache_view->virtual_pixel_method,x,y,1,1,cache_view->nexus_info[id],
+    exception);
+  if (pixels == (const PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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 long x,
+%        const long 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 long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  *pixel=cache_view->image->background_color;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  pixels=GetVirtualPixelsFromNexus(cache_view->image,virtual_pixel_method,x,y,1,
+    1,cache_view->nexus_info[id],exception);
+  if (pixels == (const PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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:
+%
+%      PixelPacket *QueueCacheViewAuthenticPixels(CacheView *cache_view,
+%        const long x,const long y,const unsigned long columns,
+%        const unsigned long 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 PixelPacket *QueueCacheViewAuthenticPixels(CacheView *cache_view,
+  const long x,const long y,const unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+  Cache
+    cache;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  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=GetImagePixelCache(cache_view->image,MagickFalse,exception);
+  if (cache == (Cache) NULL)
+    return((PixelPacket *) NULL);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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)
+{
+  long
+    id;
+
+  MagickBooleanType
+    status;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_view->number_threads);
+  status=SyncAuthenticPixelCacheNexus(cache_view->image,
+    cache_view->nexus_info[id],exception);
+  return(status);
+}
diff --git a/magick/cache-view.h b/magick/cache-view.h
new file mode 100644
index 0000000..850d95a
--- /dev/null
+++ b/magick/cache-view.h
@@ -0,0 +1,103 @@
+/*
+  Copyright 1999-2009 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 "magick/pixel.h"
+
+typedef enum
+{
+  UndefinedVirtualPixelMethod,
+  BackgroundVirtualPixelMethod,
+  ConstantVirtualPixelMethod,  /* deprecated */
+  DitherVirtualPixelMethod,
+  EdgeVirtualPixelMethod,
+  MirrorVirtualPixelMethod,
+  RandomVirtualPixelMethod,
+  TileVirtualPixelMethod,
+  TransparentVirtualPixelMethod,
+  MaskVirtualPixelMethod,
+  BlackVirtualPixelMethod,
+  GrayVirtualPixelMethod,
+  WhiteVirtualPixelMethod,
+  HorizontalTileVirtualPixelMethod,
+  VerticalTileVirtualPixelMethod,
+  HorizontalTileEdgeVirtualPixelMethod,
+  VerticalTileEdgeVirtualPixelMethod,
+  CheckerTileVirtualPixelMethod
+} VirtualPixelMethod;
+
+typedef struct _CacheView
+  CacheView;
+
+extern MagickExport ClassType
+  GetCacheViewStorageClass(const CacheView *);
+
+extern MagickExport ColorspaceType
+  GetCacheViewColorspace(const CacheView *);
+
+extern MagickExport const IndexPacket
+  *GetCacheViewVirtualIndexQueue(const CacheView *);
+
+extern MagickExport const PixelPacket
+  *GetCacheViewVirtualPixels(const CacheView *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *),
+  *GetCacheViewVirtualPixelQueue(const CacheView *);
+
+extern MagickExport ExceptionInfo
+  *GetCacheViewException(const CacheView *);
+
+extern MagickExport IndexPacket
+  *GetCacheViewAuthenticIndexQueue(CacheView *);
+
+extern MagickExport MagickBooleanType
+  GetOneCacheViewVirtualPixel(const CacheView *,const long,const long,
+    PixelPacket *,ExceptionInfo *),
+  GetOneCacheViewVirtualMethodPixel(const CacheView *,
+    const VirtualPixelMethod,const long,const long,PixelPacket *,
+    ExceptionInfo *),
+  GetOneCacheViewAuthenticPixel(const CacheView *,const long,const long,
+    PixelPacket *,ExceptionInfo *),
+  SetCacheViewStorageClass(CacheView *,const ClassType),
+  SetCacheViewVirtualPixelMethod(CacheView *,const VirtualPixelMethod),
+  SyncCacheViewAuthenticPixels(CacheView *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetCacheViewExtent(const CacheView *);
+
+extern MagickExport PixelPacket
+  *GetCacheViewAuthenticPixelQueue(CacheView *),
+  *GetCacheViewAuthenticPixels(CacheView *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *),
+  *QueueCacheViewAuthenticPixels(CacheView *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *);
+
+extern MagickExport CacheView
+  *AcquireCacheView(const Image *),
+  *CloneCacheView(const CacheView *),
+  *DestroyCacheView(CacheView *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/cache.c b/magick/cache.c
new file mode 100644
index 0000000..f187793
--- /dev/null
+++ b/magick/cache.c
@@ -0,0 +1,5306 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/color-private.h"
+#include "magick/composite-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/utility.h"
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+#include "zlib.h"
+#endif
+
+/*
+  Typedef declarations.
+*/
+typedef struct _MagickModulo
+{
+  long
+    quotient,
+    remainder;
+} MagickModulo;
+
+struct _NexusInfo
+{
+  MagickBooleanType
+    mapped;
+
+  RectangleInfo
+    region;
+
+  MagickSizeType
+    length;
+
+  PixelPacket
+    *cache,
+    *pixels;
+
+  IndexPacket
+    *indexes;
+
+  unsigned long
+    signature;
+};
+
+/*
+  Forward declarations.
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const IndexPacket
+  *GetVirtualIndexesFromCache(const Image *);
+
+static const PixelPacket
+  *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const long,
+    const long,const unsigned long,const unsigned long,ExceptionInfo *),
+  *GetVirtualPixelsCache(const Image *);
+
+static MagickBooleanType
+  GetOneAuthenticPixelFromCache(Image *,const long,const long,PixelPacket *,
+    ExceptionInfo *),
+  GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
+    const long,const long,PixelPacket *,ExceptionInfo *),
+  OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
+  ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
+  WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
+
+static PixelPacket
+  *GetAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
+    const unsigned long,ExceptionInfo *),
+  *QueueAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
+    const unsigned long,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;
+
+static time_t
+  cache_timer = 0;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 unsigned long number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o number_threads: the number of nexus threads.
+%
+*/
+MagickExport Cache AcquirePixelCache(const unsigned long number_threads)
+{
+  CacheInfo
+    *cache_info;
+
+  cache_info=(CacheInfo *) AcquireAlignedMemory(1,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->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");
+  GetPixelCacheMethods(&cache_info->methods);
+  cache_info->reference_count=1;
+  cache_info->semaphore=AllocateSemaphoreInfo();
+  cache_info->disk_semaphore=AllocateSemaphoreInfo();
+  cache_info->debug=IsEventLogging();
+  cache_info->signature=MagickSignature;
+  if ((cache_resources == (SplayTreeInfo *) NULL) &&
+      (instantiate_cache == MagickFalse))
+    {
+      AcquireSemaphoreInfo(&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;
+        }
+      RelinquishSemaphoreInfo(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 unsigned long number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o number_threads: the number of nexus threads.
+%
+*/
+MagickExport NexusInfo **AcquirePixelCacheNexus(
+  const unsigned long number_threads)
+{
+  register long
+    i;
+
+  NexusInfo
+    **nexus_info;
+
+  nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
+    sizeof(*nexus_info));
+  if (nexus_info == (NexusInfo **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  for (i=0; i < (long) 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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.  The method 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 PixelPacket
+    *__restrict r;
+
+  register IndexPacket
+    *__restrict nexus_indexes,
+    *__restrict indexes;
+
+  register long
+    i;
+
+  register PixelPacket
+    *__restrict p,
+    *__restrict q;
+
+  /*
+    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 *) GetImagePixelCache(image,MagickTrue,exception);
+  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=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
+    nexus_info->region.width,nexus_info->region.height,image_nexus[0],
+    exception);
+  indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
+  q=nexus_info->pixels;
+  nexus_indexes=nexus_info->indexes;
+  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 < (long) number_pixels; i++)
+  {
+    if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
+      break;
+    if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
+      {
+        q->red=p->red;
+        q->green=p->green;
+        q->blue=p->blue;
+        q->opacity=p->opacity;
+        if (cache_info->active_index_channel != MagickFalse)
+          nexus_indexes[i]=indexes[i];
+      }
+    p++;
+    q++;
+    r++;
+  }
+  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
+  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
+  if (i < (long) 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 N e x u s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClonePixelCacheNexus() clones the source cache nexus to the destination
+%  nexus.
+%
+%  The format of the ClonePixelCacheNexus() method is:
+%
+%      MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
+%        CacheInfo *source,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o destination: the destination cache nexus.
+%
+%    o source: the source cache nexus.
+%
+%    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=(PixelPacket *) AcquireMagickMemory((size_t)
+    nexus_info->length);
+  if (nexus_info->cache == (PixelPacket *) NULL)
+    {
+      nexus_info->mapped=MagickTrue;
+      nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
+        nexus_info->length);
+    }
+  if (nexus_info->cache == (PixelPacket *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
+  CacheInfo *source,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    number_pixels;
+
+  register long
+    i;
+
+  register const NexusInfo
+    *p;
+
+  register NexusInfo
+    *q;
+
+  status=MagickTrue;
+  for (i=0; i < (long) source->number_threads; i++)
+  {
+    p=source->nexus_info[i];
+    q=destination->nexus_info[i];
+    q->mapped=p->mapped;
+    q->region=p->region;
+    q->length=p->length;
+    q->cache=p->cache;
+    q->pixels=p->pixels;
+    q->indexes=p->indexes;
+    if (p->cache != (PixelPacket *) NULL)
+      {
+        status=AcquireCacheNexusPixels(source,q,exception);
+        if (status != MagickFalse)
+          {
+            (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
+            q->pixels=q->cache;
+            q->indexes=(IndexPacket *) NULL;
+            number_pixels=(MagickSizeType) q->region.width*q->region.height;
+            if (p->indexes != (IndexPacket *) NULL)
+              q->indexes=(IndexPacket *) (q->pixels+number_pixels);
+          }
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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;
+
+  AcquireSemaphoreInfo(&cache_info->disk_semaphore);
+  status=close(cache_info->file);
+  cache_info->file=(-1);
+  RelinquishMagickResource(FileResource,1);
+  RelinquishSemaphoreInfo(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;
+  AcquireSemaphoreInfo(&cache_semaphore);
+  if (cache_resources == (SplayTreeInfo *) NULL)
+    {
+      RelinquishSemaphoreInfo(cache_semaphore);
+      return;
+    }
+  ResetSplayTreeIterator(cache_resources);
+  p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  while (p != (CacheInfo *) NULL)
+  {
+    if ((p->type == DiskCache) && (p->file != -1))
+      {
+        if (IsMagickThreadEqual(p->id) != MagickFalse)
+          break;
+      }
+    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  }
+  for (q=p; p != (CacheInfo *) NULL; )
+  {
+    if ((p->type == DiskCache) && (p->file != -1) &&
+        (p->timestamp < q->timestamp))
+      {
+        if (IsMagickThreadEqual(p->id) != MagickFalse)
+          q=p;
+      }
+    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  }
+  if (q != (CacheInfo *) NULL)
+    (void) ClosePixelCacheOnDisk(q);  /* relinquish least recently used cache */
+  RelinquishSemaphoreInfo(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.
+  */
+  AcquireSemaphoreInfo(&cache_info->disk_semaphore);
+  if (cache_info->file != -1)
+    {
+      RelinquishSemaphoreInfo(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)
+    {
+      RelinquishSemaphoreInfo(cache_info->disk_semaphore);
+      return(MagickFalse);
+    }
+  (void) AcquireMagickResource(FileResource,1);
+  cache_info->file=file;
+  cache_info->timestamp=time(0);
+  RelinquishSemaphoreInfo(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;
+
+#if !defined(MAGICKCORE_HAVE_PREAD)
+  (void) LockSemaphoreInfo(cache_info->disk_semaphore);
+  cache_info->timestamp=time(0);
+  if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
+    {
+      (void) 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)
+  (void) 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;
+
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+  (void) LockSemaphoreInfo(cache_info->disk_semaphore);
+  cache_info->timestamp=time(0);
+  if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
+    {
+      (void) 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)
+  (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
+#endif
+  return(i);
+}
+
+static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset,
+    source_offset;
+
+  MagickSizeType
+    length;
+
+  register long
+    y;
+
+  register PixelPacket
+    *__restrict pixels;
+
+  unsigned long
+    columns,
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
+  if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
+    {
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        clone_info->cache_filename);
+      return(MagickFalse);
+    }
+  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+    {
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
+  rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
+  if ((clone_info->active_index_channel != MagickFalse) &&
+      (cache_info->active_index_channel != MagickFalse))
+    {
+      register IndexPacket
+        *indexes;
+
+      /*
+        Clone cache indexes.
+      */
+      length=MagickMax(clone_info->columns,cache_info->columns)*
+        sizeof(*indexes);
+      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
+      if (indexes == (IndexPacket *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      (void) ResetMagickMemory(indexes,0,(size_t) length);
+      length=columns*sizeof(*indexes);
+      source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
+        sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
+      offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
+        sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
+      for (y=0; y < (long) rows; y++)
+      {
+        source_offset-=cache_info->columns*sizeof(*indexes);
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
+          length,(unsigned char *) indexes);
+        if ((MagickSizeType) count != length)
+          break;
+        offset-=clone_info->columns*sizeof(*indexes);
+        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+          (unsigned char *) indexes);
+        if ((MagickSizeType) count != length)
+          break;
+      }
+      if (y < (long) rows)
+        {
+          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+          ThrowFileException(exception,CacheError,"UnableToCloneCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if (clone_info->columns > cache_info->columns)
+        {
+          length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
+          (void) ResetMagickMemory(indexes,0,(size_t) length);
+          offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
+            sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
+          for (y=0; y < (long) rows; y++)
+          {
+            offset-=clone_info->columns*sizeof(*indexes);
+            count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
+              length,(unsigned char *) indexes);
+            if ((MagickSizeType) count != length)
+              break;
+          }
+          if (y < (long) rows)
+            {
+              indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+              ThrowFileException(exception,CacheError,"UnableToCloneCache",
+                cache_info->cache_filename);
+              return(MagickFalse);
+            }
+        }
+      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+    }
+  /*
+    Clone cache pixels.
+  */
+  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
+  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
+  if (pixels == (PixelPacket *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  (void) ResetMagickMemory(pixels,0,(size_t) length);
+  length=columns*sizeof(*pixels);
+  source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
+  offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
+  for (y=0; y < (long) rows; y++)
+  {
+    source_offset-=cache_info->columns*sizeof(*pixels);
+    count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
+      length,(unsigned char *) pixels);
+    if ((MagickSizeType) count != length)
+      break;
+    offset-=clone_info->columns*sizeof(*pixels);
+    count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+      (unsigned char *) pixels);
+    if ((MagickSizeType) count != length)
+      break;
+  }
+  if (y < (long) rows)
+    {
+      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+      ThrowFileException(exception,CacheError,"UnableToCloneCache",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  if (clone_info->columns > cache_info->columns)
+    {
+      offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
+        sizeof(*pixels);
+      length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
+      (void) ResetMagickMemory(pixels,0,(size_t) length);
+      for (y=0; y < (long) rows; y++)
+      {
+        offset-=clone_info->columns*sizeof(*pixels);
+        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+          (unsigned char *) pixels);
+        if ((MagickSizeType) count != length)
+          break;
+      }
+      if (y < (long) rows)
+        {
+          pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+          ThrowFileException(exception,CacheError,"UnableToCloneCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+    }
+  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+  return(MagickTrue);
+}
+
+static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    length;
+
+  register long
+    y;
+
+  register PixelPacket
+    *__restrict pixels,
+    *__restrict q;
+
+  unsigned long
+    columns,
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
+  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+    {
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
+  rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
+  if ((clone_info->active_index_channel != MagickFalse) &&
+      (cache_info->active_index_channel != MagickFalse))
+    {
+      register IndexPacket
+        *indexes,
+        *q;
+
+      /*
+        Clone cache indexes.
+      */
+      length=MagickMax(clone_info->columns,cache_info->columns)*
+        sizeof(*indexes);
+      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
+      if (indexes == (IndexPacket *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      (void) ResetMagickMemory(indexes,0,(size_t) length);
+      length=columns*sizeof(IndexPacket);
+      offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
+        sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
+      q=clone_info->indexes+clone_info->columns*rows;
+      for (y=0; y < (long) rows; y++)
+      {
+        offset-=cache_info->columns*sizeof(IndexPacket);
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
+          length,(unsigned char *) indexes);
+        if ((MagickSizeType) count != length)
+          break;
+        q-=clone_info->columns;
+        (void) CopyMagickMemory(q,indexes,(size_t) length);
+        if ((MagickSizeType) count != length)
+          break;
+      }
+      if (y < (long) rows)
+        {
+          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+          ThrowFileException(exception,CacheError,"UnableToCloneCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+    }
+  /*
+    Clone cache pixels.
+  */
+  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
+  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
+  if (pixels == (PixelPacket *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  (void) ResetMagickMemory(pixels,0,(size_t) length);
+  length=columns*sizeof(*pixels);
+  offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
+  q=clone_info->pixels+clone_info->columns*rows;
+  for (y=0; y < (long) rows; y++)
+  {
+    offset-=cache_info->columns*sizeof(*pixels);
+    count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
+      (unsigned char *) pixels);
+    if ((MagickSizeType) count != length)
+      break;
+    q-=clone_info->columns;
+    (void) CopyMagickMemory(q,pixels,(size_t) length);
+  }
+  if (y < (long) rows)
+    {
+      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+      ThrowFileException(exception,CacheError,"UnableToCloneCache",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+  return(MagickTrue);
+}
+
+static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    length;
+
+  register long
+    y;
+
+  register PixelPacket
+    *__restrict p,
+    *__restrict pixels;
+
+  unsigned long
+    columns,
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
+  if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
+    {
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        clone_info->cache_filename);
+      return(MagickFalse);
+    }
+  columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
+  rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
+  if ((clone_info->active_index_channel != MagickFalse) &&
+      (cache_info->active_index_channel != MagickFalse))
+    {
+      register IndexPacket
+        *p,
+        *indexes;
+
+      /*
+        Clone cache indexes.
+      */
+      length=MagickMax(clone_info->columns,cache_info->columns)*
+        sizeof(*indexes);
+      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
+      if (indexes == (IndexPacket *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      (void) ResetMagickMemory(indexes,0,(size_t) length);
+      length=columns*sizeof(*indexes);
+      p=cache_info->indexes+cache_info->columns*rows;
+      offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
+        sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
+      for (y=0; y < (long) rows; y++)
+      {
+        p-=cache_info->columns;
+        (void) CopyMagickMemory(indexes,p,(size_t) length);
+        offset-=clone_info->columns*sizeof(*indexes);
+        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+          (unsigned char *) indexes);
+        if ((MagickSizeType) count != length)
+          break;
+      }
+      if (y < (long) rows)
+        {
+          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+          ThrowFileException(exception,CacheError,"UnableToCloneCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if (clone_info->columns > cache_info->columns)
+        {
+          length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
+          (void) ResetMagickMemory(indexes,0,(size_t) length);
+          offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
+            sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
+          for (y=0; y < (long) rows; y++)
+          {
+            offset-=clone_info->columns*sizeof(*indexes);
+            count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
+              length,(unsigned char *) indexes);
+            if ((MagickSizeType) count != length)
+              break;
+          }
+          if (y < (long) rows)
+            {
+              indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+              ThrowFileException(exception,CacheError,"UnableToCloneCache",
+                cache_info->cache_filename);
+              return(MagickFalse);
+            }
+        }
+      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
+    }
+  /*
+    Clone cache pixels.
+  */
+  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
+  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
+  if (pixels == (PixelPacket *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  (void) ResetMagickMemory(pixels,0,(size_t) length);
+  length=columns*sizeof(*pixels);
+  p=cache_info->pixels+cache_info->columns*rows;
+  offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
+  for (y=0; y < (long) rows; y++)
+  {
+    p-=cache_info->columns;
+    (void) CopyMagickMemory(pixels,p,(size_t) length);
+    offset-=clone_info->columns*sizeof(*pixels);
+    count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+      (unsigned char *) pixels);
+    if ((MagickSizeType) count != length)
+      break;
+  }
+  if (y < (long) rows)
+    {
+      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+      ThrowFileException(exception,CacheError,"UnableToCloneCache",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  if (clone_info->columns > cache_info->columns)
+    {
+      offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
+        sizeof(*pixels);
+      length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
+      (void) ResetMagickMemory(pixels,0,(size_t) length);
+      for (y=0; y < (long) rows; y++)
+      {
+        offset-=clone_info->columns*sizeof(*pixels);
+        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
+          (unsigned char *) pixels);
+        if ((MagickSizeType) count != length)
+          break;
+      }
+      if (y < (long) rows)
+        {
+          pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+          ThrowFileException(exception,CacheError,"UnableToCloneCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+    }
+  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
+  return(MagickTrue);
+}
+
+static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
+{
+  register long
+    y;
+
+  register PixelPacket
+    *__restrict pixels,
+    *__restrict source_pixels;
+
+  size_t
+    length;
+
+  unsigned long
+    columns,
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
+  columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
+  rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
+  if ((clone_info->active_index_channel != MagickFalse) &&
+      (cache_info->active_index_channel != MagickFalse))
+    {
+      register IndexPacket
+        *indexes,
+        *source_indexes;
+
+      /*
+        Clone cache indexes.
+      */
+      length=columns*sizeof(*indexes);
+      if (clone_info->columns == cache_info->columns)
+        (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
+          length*rows);
+      else
+        {
+          source_indexes=cache_info->indexes+cache_info->columns*rows;
+          indexes=clone_info->indexes+clone_info->columns*rows;
+          for (y=0; y < (long) rows; y++)
+          {
+            source_indexes-=cache_info->columns;
+            indexes-=clone_info->columns;
+            (void) CopyMagickMemory(indexes,source_indexes,length);
+          }
+          if (clone_info->columns > cache_info->columns)
+            {
+              length=(clone_info->columns-cache_info->columns)*
+                sizeof(*indexes);
+              indexes=clone_info->indexes+clone_info->columns*rows+
+                cache_info->columns;
+              for (y=0; y < (long) rows; y++)
+              {
+                indexes-=clone_info->columns;
+                (void) ResetMagickMemory(indexes,0,length);
+              }
+            }
+        }
+    }
+  /*
+    Clone cache pixels.
+  */
+  length=columns*sizeof(*pixels);
+  if (clone_info->columns == cache_info->columns)
+    (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
+  else
+    {
+      source_pixels=cache_info->pixels+cache_info->columns*rows;
+      pixels=clone_info->pixels+clone_info->columns*rows;
+      for (y=0; y < (long) rows; y++)
+      {
+        source_pixels-=cache_info->columns;
+        pixels-=clone_info->columns;
+        (void) CopyMagickMemory(pixels,source_pixels,length);
+      }
+      if (clone_info->columns > cache_info->columns)
+        {
+          length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
+          pixels=clone_info->pixels+clone_info->columns*rows+
+            cache_info->columns;
+          for (y=0; y < (long) rows; y++)
+          {
+            pixels-=clone_info->columns;
+            (void) ResetMagickMemory(pixels,0,length);
+          }
+        }
+    }
+  return(MagickTrue);
+}
+
+static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
+    return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
+  if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
+    return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
+  if (cache_info->type == DiskCache)
+    return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
+  return(CloneMemoryToDiskPixelCache(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)
+    return;
+  cache_info->methods.destroy_pixel_handler(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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=(PixelPacket *) RelinquishMagickMemory(
+          cache_info->pixels);
+      else
+        cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
+          (size_t) cache_info->length);
+      RelinquishMagickResource(MemoryResource,cache_info->length);
+      break;
+    }
+    case MapCache:
+    {
+      cache_info->pixels=(PixelPacket *) 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->indexes=(IndexPacket *) NULL;
+}
+
+MagickExport Cache DestroyPixelCache(Cache cache)
+{
+  CacheInfo
+    *cache_info;
+
+  CacheType
+    type;
+
+  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);
+  (void) LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count--;
+  if (cache_info->reference_count != 0)
+    {
+      (void) UnlockSemaphoreInfo(cache_info->semaphore);
+      return((Cache) NULL);
+    }
+  (void) UnlockSemaphoreInfo(cache_info->semaphore);
+  if (cache_resources != (SplayTreeInfo *) NULL)
+    (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
+  type=cache_info->type;
+  RelinquishPixelCachePixels(cache_info);
+  if ((type == MapCache) || (type == DiskCache))
+    (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->debug != MagickFalse)
+    {
+      char
+        message[MaxTextExtent];
+
+      (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
+        cache_info->filename);
+      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
+    }
+  if (cache_info->random_info != (RandomInfo *) NULL)
+    cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
+  cache_info->signature=(~MagickSignature);
+  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 *) RelinquishAlignedMemory(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 unsigned long 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=(PixelPacket *) NULL;
+  nexus_info->pixels=(PixelPacket *) NULL;
+  nexus_info->indexes=(IndexPacket *) NULL;
+  nexus_info->length=0;
+  nexus_info->mapped=MagickFalse;
+}
+
+MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
+  const unsigned long number_threads)
+{
+  register long
+    i;
+
+  assert(nexus_info != (NexusInfo **) NULL);
+  for (i=0; i < (long) number_threads; i++)
+  {
+    if (nexus_info[i]->cache != (PixelPacket *) NULL)
+      RelinquishCacheNexusPixels(nexus_info[i]);
+    nexus_info[i]->signature=(~MagickSignature);
+    nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
+  }
+  nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
+  return(nexus_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P i x e l C a c h e R e s o u r c e s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPixelCacheResources() destroys the cache resources.
+%
+%  The format of the DestroyPixelCacheResources() method is:
+%
+%      DestroyPixelCacheResources(void)
+%
+*/
+MagickExport void DestroyPixelCacheResources(void)
+{
+  AcquireSemaphoreInfo(&cache_semaphore);
+  if (cache_resources != (SplayTreeInfo *) NULL)
+    cache_resources=DestroySplayTree(cache_resources);
+  instantiate_cache=MagickFalse;
+  RelinquishSemaphoreInfo(cache_semaphore);
+  DestroySemaphoreInfo(&cache_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c I n d e x e s F r o m C a c h e                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticIndexesFromCache() returns the indexes associated with the last
+%  call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
+%
+%  The format of the GetAuthenticIndexesFromCache() method is:
+%
+%      IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  IndexPacket
+    *indexes;
+
+  long
+    id;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_info->number_threads);
+  indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
+  return(indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t A u t h e n t i c I n d e x Q u e u e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticIndexQueue() returns the authentic black channel or the colormap
+%  indexes associated with the last call to QueueAuthenticPixels() or
+%  GetVirtualPixels().  NULL is returned if the black channel or colormap
+%  indexes are not available.
+%
+%  The format of the GetAuthenticIndexQueue() method is:
+%
+%      IndexPacket *GetAuthenticIndexQueue(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport IndexPacket *GetAuthenticIndexQueue(const 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.get_authentic_indexes_from_handler ==
+       (GetAuthenticIndexesFromHandler) NULL)
+    return((IndexPacket *) NULL);
+  return(cache_info->methods.get_authentic_indexes_from_handler(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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:
+%
+%      PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 IsNexusInCore(const CacheInfo *cache_info,
+  NexusInfo *nexus_info)
+{
+  MagickOffsetType
+    offset;
+
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  if (nexus_info->pixels != (cache_info->pixels+offset))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  PixelPacket
+    *pixels;
+
+  /*
+    Transfer pixels from the cache.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
+  if (pixels == (PixelPacket *) NULL)
+    return((PixelPacket *) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
+    return(pixels);
+  if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
+    return((PixelPacket *) NULL);
+  if (cache_info->active_index_channel != MagickFalse)
+    if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
+      return((PixelPacket *) 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:
+%
+%      PixelPacket *GetAuthenticPixelsFromCache(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_info->number_threads);
+  pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 with the
+%  last call to QueueAuthenticPixels() or GetAuthenticPixels().
+%
+%  The format of the GetAuthenticPixelQueue() method is:
+%
+%      PixelPacket *GetAuthenticPixelQueue(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport PixelPacket *GetAuthenticPixelQueue(const 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.get_authentic_pixels_from_handler ==
+      (GetAuthenticPixelsFromHandler) NULL)
+    return((PixelPacket *) NULL);
+  return(cache_info->methods.get_authentic_pixels_from_handler(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 PixelPacket 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 RAM, or in a memory-mapped file. The returned pointer
+%  should *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket. If the image type is CMYK or if the storage class is
+%  PseduoClass, call GetAuthenticIndexQueue() after invoking
+%  GetAuthenticPixels() to obtain the black color component or colormap indexes
+%  (of type IndexPacket) corresponding to the region.  Once the PixelPacket
+%  (and/or IndexPacket) 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:
+%
+%      PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
+%        const unsigned long columns,const unsigned long 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 PixelPacket *GetAuthenticPixels(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  PixelPacket
+    *pixels;
+
+  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);
+  if (cache_info->methods.get_authentic_pixels_handler ==
+      (GetAuthenticPixelsHandler) NULL)
+    return((PixelPacket *) NULL);
+  pixels=cache_info->methods.get_authentic_pixels_handler(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 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:
+%
+%      PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
+  if (cache_info == (Cache) NULL)
+    return((PixelPacket *) NULL);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 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;
+
+  long
+    id;
+
+  MagickSizeType
+    extent;
+
+  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);
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_info->number_threads);
+  extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
+  return(extent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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) ||
+      (cache_info->nexus_info == (NexusInfo **) NULL) ||
+      (cache_info->number_threads < GetOpenMPMaximumThreads()))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+MagickExport Cache GetImagePixelCache(Image *image,
+  const MagickBooleanType clone,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickSizeType
+    time_limit;
+
+  MagickBooleanType
+    status;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  status=MagickTrue;
+  (void) LockSemaphoreInfo(image->semaphore);
+  time_limit=GetMagickResourceLimit(TimeResource);
+  if (cache_timer == 0)
+    cache_timer=time((time_t *) NULL);
+  if ((time_limit != MagickResourceInfinity) &&
+      ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
+    ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  (void) LockSemaphoreInfo(cache_info->semaphore);
+  if (cache_info->reference_count > 1)
+    {
+      Image
+        clone_image;
+
+      CacheInfo
+        *clone_info;
+
+      /*
+        Clone pixel cache.
+      */
+      clone_image=(*image);
+      clone_image.cache=ClonePixelCache(cache_info);
+      clone_info=(CacheInfo *) clone_image.cache;
+      status=ClonePixelCacheNexus(cache_info,clone_info,exception);
+      if (status != MagickFalse)
+        {
+          status=OpenPixelCache(&clone_image,IOMode,exception);
+          if (status != MagickFalse)
+            {
+              if (clone != MagickFalse)
+                status=ClonePixelCachePixels(clone_info,cache_info,exception);
+              if (status != MagickFalse)
+                {
+                  cache_info->reference_count--;
+                  image->cache=clone_image.cache;
+                }
+            }
+        }
+    }
+  (void) UnlockSemaphoreInfo(cache_info->semaphore);
+  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);
+    }
+  (void) 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 long x,
+%        const long 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 long x,
+  const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  GetOneAuthenticPixelFromHandler
+    get_one_authentic_pixel_from_handler;
+
+  MagickBooleanType
+    status;
+
+  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);
+  *pixel=image->background_color;
+  get_one_authentic_pixel_from_handler=
+    cache_info->methods.get_one_authentic_pixel_from_handler;
+  if (get_one_authentic_pixel_from_handler ==
+      (GetOneAuthenticPixelFromHandler) NULL)
+    return(MagickFalse);
+  status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
+    pixel,exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 long x,const long 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 long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  PixelPacket
+    *pixels;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *pixel=image->background_color;
+  pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
+  if (pixels == (PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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 long x,const long y,MagickPixelPacket *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 long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *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);
+  GetMagickPixelPacket(image,pixel);
+  p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
+    exception);
+  if (p == (const PixelPacket *) NULL)
+    return(MagickFalse);
+  indexes=GetVirtualIndexQueue(image);
+  SetMagickPixelPacket(image,p,indexes,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 long x,
+%        const long 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 long x,const long y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  GetOneVirtualPixelFromHandler
+    get_one_virtual_pixel_from_handler;
+
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  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;
+  get_one_virtual_pixel_from_handler=
+    cache_info->methods.get_one_virtual_pixel_from_handler;
+  if (get_one_virtual_pixel_from_handler ==
+      (GetOneVirtualPixelFromHandler) NULL)
+    return(MagickFalse);
+  status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
+    pixel,exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long x,
+%        const long 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 long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  GetOneVirtualPixelFromHandler
+    get_one_virtual_pixel_from_handler;
+
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  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;
+  get_one_virtual_pixel_from_handler=
+    cache_info->methods.get_one_virtual_pixel_from_handler;
+  if (get_one_virtual_pixel_from_handler ==
+      (GetOneVirtualPixelFromHandler) NULL)
+    return(MagickFalse);
+  status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
+    image),x,y,pixel,exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 VirtualPixelPacket method,const long x,const long 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 long x,const long y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const PixelPacket
+    *pixels;
+
+  *pixel=image->background_color;
+  pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
+  if (pixels == (const PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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_indexes_from_handler=GetVirtualIndexesFromCache;
+  cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
+  cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
+  cache_methods->get_authentic_indexes_from_handler=
+    GetAuthenticIndexesFromCache;
+  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 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;
+
+  if (cache == (Cache) NULL)
+    return(0);
+  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 I n d e x e s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheNexusIndexes() returns the indexes associated with the
+%  specified cache nexus.
+%
+%  The format of the GetPixelCacheNexusIndexes() method is:
+%
+%      IndexPacket *GetPixelCacheNexusIndexes(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 indexes.
+%
+*/
+MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  if (cache == (Cache) NULL)
+    return((IndexPacket *) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((IndexPacket *) NULL);
+  return(nexus_info->indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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:
+%
+%      PixelPacket *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 PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  if (cache == (Cache) NULL)
+    return((PixelPacket *) 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_info->storage_class == UndefinedClass)
+    return((PixelPacket *) NULL);
+  return(nexus_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e S t o r a 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 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);
+  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);
+  return(cache_info->virtual_pixel_method);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l I n d e x e s F r o m C a c h e                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualIndexesFromCache() returns the indexes associated with the last
+%  call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
+%
+%  The format of the GetVirtualIndexesFromCache() method is:
+%
+%      IndexPacket *GetVirtualIndexesFromCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const IndexPacket
+    *indexes;
+
+  long
+    id;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_info->number_threads);
+  indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
+  return(indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l I n d e x e s F r o m N e x u s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualIndexesFromNexus() returns the indexes associated with the
+%  specified cache nexus.
+%
+%  The format of the GetVirtualIndexesFromNexus() method is:
+%
+%      const IndexPacket *GetVirtualIndexesFromNexus(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 indexes.
+%
+*/
+MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  if (cache == (Cache) NULL)
+    return((IndexPacket *) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((IndexPacket *) NULL);
+  return(nexus_info->indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V i r t u a l I n d e x Q u e u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualIndexQueue() returns the virtual black channel or the
+%  colormap indexes associated with the last call to QueueAuthenticPixels() or
+%  GetVirtualPixels().  NULL is returned if the black channel or colormap
+%  indexes are not available.
+%
+%  The format of the GetVirtualIndexQueue() method is:
+%
+%      const IndexPacket *GetVirtualIndexQueue(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const IndexPacket *GetVirtualIndexQueue(const 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.get_virtual_indexes_from_handler ==
+      (GetVirtualIndexesFromHandler) NULL)
+    return((IndexPacket *) NULL);
+  return(cache_info->methods.get_virtual_indexes_from_handler(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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:
+%
+%      PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
+%        const VirtualPixelMethod method,const long x,const long y,
+%        const unsigned long columns,const unsigned long 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 long
+  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 long DitherX(const unsigned long columns,const long x)
+{
+  long
+    index;
+
+  index=x+DitherMatrix[x & 0x07]-32L;
+  if (index < 0L)
+    return(0L);
+  if (index >= (long) columns)
+    return((long) columns-1L);
+  return(index);
+}
+
+static inline long DitherY(const unsigned long rows,const long y)
+{
+  long
+    index;
+
+  index=y+DitherMatrix[y & 0x07]-32L;
+  if (index < 0L)
+    return(0L);
+  if (index >= (long) rows)
+    return((long) rows-1L);
+  return(index);
+}
+
+static inline long EdgeX(const unsigned long columns,const long x)
+{
+  if (x < 0L)
+    return(0L);
+  if (x >= (long) columns)
+    return((long) columns-1L);
+  return(x);
+}
+
+static inline long EdgeY(const unsigned long rows,const long y)
+{
+  if (y < 0L)
+    return(0L);
+  if (y >= (long) rows)
+    return((long) rows-1L);
+  return(y);
+}
+
+static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
+{
+  return((long) (columns*GetPseudoRandomValue(random_info)));
+}
+
+static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
+{
+  return((long) (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 long offset,
+  const unsigned long extent)
+{
+  MagickModulo
+    modulo;
+
+  modulo.quotient=offset/(long) extent;
+  if (offset < 0L)
+    modulo.quotient--;
+  modulo.remainder=offset-modulo.quotient*(long) extent;
+  return(modulo);
+}
+
+MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
+  const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  NexusInfo
+    **virtual_nexus;
+
+  PixelPacket
+    *pixels,
+    virtual_pixel;
+
+  RectangleInfo
+    region;
+
+  register const IndexPacket
+    *__restrict nexus_indexes;
+
+  register const PixelPacket
+    *__restrict p;
+
+  register IndexPacket
+    *__restrict indexes;
+
+  register long
+    u,
+    v;
+
+  register PixelPacket
+    *__restrict q;
+
+  /*
+    Acquire pixels.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  if (cache_info->type == UndefinedCache)
+    return((const PixelPacket *) NULL);
+  region.x=x;
+  region.y=y;
+  region.width=columns;
+  region.height=rows;
+  pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
+  if (pixels == (PixelPacket *) NULL)
+    return((const PixelPacket *) NULL);
+  offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
+  length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
+  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
+    if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
+        (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
+      {
+        MagickBooleanType
+          status;
+
+        /*
+          Pixel request is inside cache extents.
+        */
+        if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
+          return(pixels);
+        status=ReadPixelCachePixels(cache_info,nexus_info,exception);
+        if (status == MagickFalse)
+          return((const PixelPacket *) NULL);
+        if ((cache_info->storage_class == PseudoClass) ||
+            (cache_info->colorspace == CMYKColorspace))
+          {
+            status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
+            if (status == MagickFalse)
+              return((const PixelPacket *) NULL);
+          }
+        return(pixels);
+      }
+  /*
+    Pixel request is outside cache extents.
+  */
+  q=pixels;
+  indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
+  virtual_nexus=AcquirePixelCacheNexus(1);
+  if (virtual_nexus == (NexusInfo **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "UnableToGetCacheNexus","`%s'",image->filename);
+      return((const PixelPacket *) NULL);
+    }
+  switch (virtual_pixel_method)
+  {
+    case BlackVirtualPixelMethod:
+    {
+      virtual_pixel.red=0;
+      virtual_pixel.green=0;
+      virtual_pixel.blue=0;
+      virtual_pixel.opacity=OpaqueOpacity;
+      break;
+    }
+    case GrayVirtualPixelMethod:
+    {
+      virtual_pixel.red=(Quantum) QuantumRange/2;
+      virtual_pixel.green=(Quantum) QuantumRange/2;
+      virtual_pixel.blue=(Quantum) QuantumRange/2;
+      virtual_pixel.opacity=(Quantum) OpaqueOpacity;
+      break;
+    }
+    case TransparentVirtualPixelMethod:
+    {
+      virtual_pixel.red=(Quantum) 0;
+      virtual_pixel.green=(Quantum) 0;
+      virtual_pixel.blue=(Quantum) 0;
+      virtual_pixel.opacity=(Quantum) TransparentOpacity;
+      break;
+    }
+    case MaskVirtualPixelMethod:
+    case WhiteVirtualPixelMethod:
+    {
+      virtual_pixel.red=(Quantum) QuantumRange;
+      virtual_pixel.green=(Quantum) QuantumRange;
+      virtual_pixel.blue=(Quantum) QuantumRange;
+      virtual_pixel.opacity=OpaqueOpacity;
+      break;
+    }
+    default:
+    {
+      virtual_pixel=image->background_color;
+      break;
+    }
+  }
+  for (v=0; v < (long) rows; v++)
+  {
+    for (u=0; u < (long) columns; u+=length)
+    {
+      length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
+      if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
+          (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
+        {
+          MagickModulo
+            x_modulo,
+            y_modulo;
+
+          /*
+            Transfer a single pixel.
+          */
+          length=(MagickSizeType) 1;
+          switch (virtual_pixel_method)
+          {
+            case BackgroundVirtualPixelMethod:
+            case ConstantVirtualPixelMethod:
+            case BlackVirtualPixelMethod:
+            case GrayVirtualPixelMethod:
+            case TransparentVirtualPixelMethod:
+            case MaskVirtualPixelMethod:
+            case WhiteVirtualPixelMethod:
+            {
+              p=(&virtual_pixel);
+              break;
+            }
+            case EdgeVirtualPixelMethod:
+            default:
+            {
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
+                1UL,1UL,virtual_nexus[0],exception);
+              break;
+            }
+            case RandomVirtualPixelMethod:
+            {
+              if (cache_info->random_info == (RandomInfo *) NULL)
+                cache_info->random_info=AcquireRandomInfo();
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                RandomX(cache_info->columns,cache_info->random_info),
+                RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
+                virtual_nexus[0],exception);
+              break;
+            }
+            case DitherVirtualPixelMethod:
+            {
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
+                1UL,1UL,virtual_nexus[0],exception);
+              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[0],
+                exception);
+              break;
+            }
+            case MirrorVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              if ((x_modulo.quotient & 0x01) == 1L)
+                x_modulo.remainder=(long) cache_info->columns-
+                  x_modulo.remainder-1L;
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              if ((y_modulo.quotient & 0x01) == 1L)
+                y_modulo.remainder=(long) cache_info->rows-
+                  y_modulo.remainder-1L;
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
+                exception);
+              break;
+            }
+            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);
+                  break;
+                }
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
+                exception);
+              break;
+            }
+            case HorizontalTileVirtualPixelMethod:
+            {
+              if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
+                {
+                  p=(&virtual_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[0],
+                exception);
+              break;
+            }
+            case VerticalTileVirtualPixelMethod:
+            {
+              if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
+                {
+                  p=(&virtual_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[0],
+                exception);
+              break;
+            }
+            case HorizontalTileEdgeVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
+                virtual_nexus[0],exception);
+              break;
+            }
+            case VerticalTileEdgeVirtualPixelMethod:
+            {
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
+                virtual_nexus[0],exception);
+              break;
+            }
+          }
+          if (p == (const PixelPacket *) NULL)
+            break;
+          *q++=(*p);
+          if (indexes != (IndexPacket *) NULL)
+            {
+              nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
+                virtual_nexus[0]);
+              if (nexus_indexes != (const IndexPacket *) NULL)
+                *indexes++=(*nexus_indexes);
+            }
+          continue;
+        }
+      /*
+        Transfer a run of pixels.
+      */
+      p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
+        (unsigned long) length,1UL,virtual_nexus[0],exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
+      q+=length;
+      if (indexes != (IndexPacket *) NULL)
+        {
+          nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
+          if (nexus_indexes != (const IndexPacket *) NULL)
+            {
+              (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
+                sizeof(*nexus_indexes));
+              indexes+=length;
+            }
+        }
+    }
+  }
+  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 PixelPacket *GetVirtualPixelCache(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *GetVirtualPixelCache(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
+  const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
+{
+  CacheInfo
+   *cache_info;
+
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 with the
+%  last call to QueueAuthenticPixels() or GetVirtualPixels().
+%
+%  The format of the GetVirtualPixelQueue() method is:
+%
+%      const PixelPacket *GetVirtualPixelQueue(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const PixelPacket *GetVirtualPixelQueue(const 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.get_virtual_pixels_handler ==
+      (GetVirtualPixelsHandler) NULL)
+    return((PixelPacket *) NULL);
+  return(cache_info->methods.get_virtual_pixels_handler(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 RAM, or in a memory-mapped file.  The
+%  returned pointer should *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
+%  the black color component or to obtain the colormap indexes (of type
+%  IndexPacket) corresponding to 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 PixelPacket *GetVirtualPixels(const Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *GetVirtualPixels(const Image *image,
+  const long x,const long y,const unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const PixelPacket
+    *pixels;
+
+  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.get_virtual_pixel_handler ==
+      (GetVirtualPixelHandler) NULL)
+    return((const PixelPacket *) NULL);
+  pixels=cache_info->methods.get_virtual_pixel_handler(image,
+    GetPixelCacheVirtualMethod(image),x,y,columns,rows,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 with the last call
+%  to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
+%
+%  The format of the GetVirtualPixelsCache() method is:
+%
+%      PixelPacket *GetVirtualPixelsCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const PixelPacket *GetVirtualPixelsCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const PixelPacket
+    *pixels;
+
+  long
+    id;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) cache_info->number_threads);
+  pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 IndexPacket *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 PixelPacket *GetVirtualPixelsNexus(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  if (cache == (Cache) NULL)
+    return((PixelPacket *) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((PixelPacket *) NULL);
+  return((const PixelPacket *) 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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  if (alpha == TransparentOpacity)
+    {
+      *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->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
+}
+
+static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickPixelPacket
+    alpha,
+    beta;
+
+  MagickSizeType
+    number_pixels;
+
+  NexusInfo
+    **clip_nexus,
+    **image_nexus;
+
+  register const PixelPacket
+    *__restrict r;
+
+  register IndexPacket
+    *__restrict nexus_indexes,
+    *__restrict indexes;
+
+  register long
+    i;
+
+  register PixelPacket
+    *__restrict p,
+    *__restrict q;
+
+  /*
+    Apply clip mask.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->mask == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
+  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=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
+    nexus_info->region.width,nexus_info->region.height,image_nexus[0],
+    exception);
+  indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
+  q=nexus_info->pixels;
+  nexus_indexes=nexus_info->indexes;
+  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);
+  GetMagickPixelPacket(image,&alpha);
+  GetMagickPixelPacket(image,&beta);
+  number_pixels=(MagickSizeType) nexus_info->region.width*
+    nexus_info->region.height;
+  for (i=0; i < (long) number_pixels; i++)
+  {
+    if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
+      break;
+    SetMagickPixelPacket(image,p,indexes+i,&alpha);
+    SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
+    MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
+      &alpha,alpha.opacity,&beta);
+    q->red=RoundToQuantum(beta.red);
+    q->green=RoundToQuantum(beta.green);
+    q->blue=RoundToQuantum(beta.blue);
+    q->opacity=RoundToQuantum(beta.opacity);
+    if (cache_info->active_index_channel != MagickFalse)
+      nexus_indexes[i]=indexes[i];
+    p++;
+    q++;
+    r++;
+  }
+  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
+  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
+  if (i < (long) 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
+%  colormap indexes, 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 AcquirePixelCachePixels(CacheInfo *cache_info)
+{
+  cache_info->mapped=MagickFalse;
+  cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
+    cache_info->length);
+  if (cache_info->pixels == (PixelPacket *) NULL)
+    {
+      cache_info->mapped=MagickTrue;
+      cache_info->pixels=(PixelPacket *) 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,format);
+      (void) FormatMagickString(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) MagickSeek(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)
+{
+  char
+    format[MaxTextExtent],
+    message[MaxTextExtent];
+
+  CacheInfo
+    *cache_info,
+    source_info;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  MagickStatusType
+    status;
+
+  size_t
+    packet_size;
+
+  unsigned long
+    columns;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->columns == 0) || (image->rows == 0))
+    ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  source_info=(*cache_info);
+  source_info.file=(-1);
+  (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
+    image->filename,GetImageIndexInList(image));
+  cache_info->rows=image->rows;
+  cache_info->columns=image->columns;
+  cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
+    (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
+  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+  packet_size=sizeof(PixelPacket);
+  if (cache_info->active_index_channel != MagickFalse)
+    packet_size+=sizeof(IndexPacket);
+  length=number_pixels*packet_size;
+  columns=(unsigned long) (length/cache_info->rows/packet_size);
+  if (cache_info->columns != columns)
+    ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
+      image->filename);
+  cache_info->length=length;
+  status=AcquireMagickResource(AreaResource,cache_info->length);
+  length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
+  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))
+        {
+          AcquirePixelCachePixels(cache_info);
+          if (cache_info->pixels == (PixelPacket *) NULL)
+            cache_info->pixels=source_info.pixels;
+          else
+            {
+              /*
+                Create memory pixel cache.
+              */
+              if (image->debug != MagickFalse)
+                {
+                  (void) FormatMagickSize(cache_info->length,format);
+                  (void) FormatMagickString(message,MaxTextExtent,
+                    "open %s (%s memory, %lux%lu %s)",cache_info->filename,
+                    cache_info->mapped != MagickFalse ? "anonymous" : "heap",
+                    cache_info->columns,cache_info->rows,format);
+                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
+                    message);
+                }
+              cache_info->storage_class=image->storage_class;
+              cache_info->colorspace=image->colorspace;
+              cache_info->type=MemoryCache;
+              cache_info->indexes=(IndexPacket *) NULL;
+              if (cache_info->active_index_channel != MagickFalse)
+                cache_info->indexes=(IndexPacket *) (cache_info->pixels+
+                  number_pixels);
+              if (source_info.storage_class != UndefinedClass)
+                {
+                  status|=ClonePixelCachePixels(cache_info,&source_info,
+                    exception);
+                  RelinquishPixelCachePixels(&source_info);
+                }
+              return(MagickTrue);
+            }
+        }
+      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 (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);
+    }
+  cache_info->storage_class=image->storage_class;
+  cache_info->colorspace=image->colorspace;
+  length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
+  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=(PixelPacket *) MapBlob(cache_info->file,mode,
+            cache_info->offset,(size_t) cache_info->length);
+          if (cache_info->pixels == (PixelPacket *) NULL)
+            {
+              cache_info->pixels=source_info.pixels;
+              cache_info->type=DiskCache;
+            }
+          else
+            {
+              /*
+                Create file-backed memory-mapped pixel cache.
+              */
+              (void) ClosePixelCacheOnDisk(cache_info);
+              cache_info->type=MapCache;
+              cache_info->mapped=MagickTrue;
+              cache_info->indexes=(IndexPacket *) NULL;
+              if (cache_info->active_index_channel != MagickFalse)
+                cache_info->indexes=(IndexPacket *) (cache_info->pixels+
+                  number_pixels);
+              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,format);
+                  (void) FormatMagickString(message,MaxTextExtent,
+                    "open %s (%s[%d], memory-mapped, %lux%lu %s)",
+                    cache_info->filename,cache_info->cache_filename,
+                    cache_info->file,cache_info->columns,cache_info->rows,
+                    format);
+                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
+                    message);
+                }
+              return(MagickTrue);
+            }
+        }
+      RelinquishMagickResource(MapResource,cache_info->length);
+    }
+  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,format);
+      (void) FormatMagickString(message,MaxTextExtent,
+        "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
+        cache_info->cache_filename,cache_info->file,cache_info->columns,
+        cache_info->rows,format);
+      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 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;
+
+  long
+    pagesize;
+
+  MagickBooleanType
+    status;
+
+  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);
+  pagesize=(-1);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+  pagesize=sysconf(_SC_PAGESIZE);
+#elif defined(MAGICKCORE_HAVE_GETPAGESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
+  pagesize=getpagesize();
+#endif
+  if (pagesize <= 0)
+    pagesize=4096;
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (attach != MagickFalse)
+    {
+      /*
+        Attach 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);
+      cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
+      *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
+      return(MagickTrue);
+    }
+  if ((cache_info->type != MemoryCache) && (cache_info->reference_count == 1))
+    {
+      (void) LockSemaphoreInfo(cache_info->semaphore);
+      if ((cache_info->type != MemoryCache) &&
+          (cache_info->reference_count == 1))
+        {
+          int
+            status;
+
+          /*
+            Usurp resident persistent pixel cache.
+          */
+          status=rename(cache_info->cache_filename,filename);
+          if (status == 0)
+            {
+              (void) CopyMagickString(cache_info->cache_filename,filename,
+                MaxTextExtent);
+              cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
+              *offset+=cache_info->length+pagesize-(cache_info->length %
+                pagesize);
+              if (image->debug != MagickFalse)
+                (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+                  "Usurp resident persistent cache");
+              (void) UnlockSemaphoreInfo(cache_info->semaphore);
+              return(MagickTrue);
+            }
+        }
+      (void) UnlockSemaphoreInfo(cache_info->semaphore);
+    }
+  /*
+    Attach 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=ClonePixelCacheNexus(cache_info,clone_info,exception);
+  if (status != MagickFalse)
+    {
+      status=OpenPixelCache(image,IOMode,exception);
+      if (status != MagickFalse)
+       status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
+    }
+  *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
+  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:
+%
+%      PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
+%        const unsigned long columns,const unsigned long 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 PixelPacket *QueueAuthenticNexus(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    number_pixels;
+
+  RectangleInfo
+    region;
+
+  /*
+    Validate pixel cache geometry.
+  */
+  cache_info=(CacheInfo *) image->cache;
+  if ((cache_info->columns == 0) && (cache_info->rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "NoPixelsDefinedInCache","`%s'",image->filename);
+      return((PixelPacket *) NULL);
+    }
+  if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
+      (y >= (long) cache_info->rows))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "PixelsAreNotAuthentic","`%s'",image->filename);
+      return((PixelPacket *) NULL);
+    }
+  offset=(MagickOffsetType) y*cache_info->columns+x;
+  if (offset < 0)
+    return((PixelPacket *) 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((PixelPacket *) 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:
+%
+%      PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  long
+    id;
+
+  PixelPacket
+    *pixels;
+
+  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
+  if (cache_info == (Cache) NULL)
+    return((PixelPacket *) NULL);
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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 intialized a pointer to a PixelPacket 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 RAM, or in a
+%  memory-mapped file. The returned pointer should *never* be deallocated
+%  by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
+%  the black color component or the colormap indexes (of type IndexPacket)
+%  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
+%  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:
+%
+%      PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
+%        const unsigned long columns,const unsigned long 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 PixelPacket *QueueAuthenticPixels(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  PixelPacket
+    *pixels;
+
+  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);
+  if (cache_info->methods.queue_authentic_pixels_handler ==
+      (QueueAuthenticPixelsHandler) NULL)
+    return((PixelPacket *) NULL);
+  pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
+    rows,exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e a d P i x e l C a c h e I n d e x e s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadPixelCacheIndexes() reads colormap indexes from the specified region of
+%  the pixel cache.
+%
+%  The format of the ReadPixelCacheIndexes() method is:
+%
+%      MagickBooleanType ReadPixelCacheIndexes(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 colormap indexes.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  register IndexPacket
+    *__restrict q;
+
+  register long
+    y;
+
+  unsigned long
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  if (cache_info->active_index_channel == MagickFalse)
+    return(MagickFalse);
+  if (IsNexusInCore(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*sizeof(IndexPacket);
+  rows=nexus_info->region.height;
+  number_pixels=length*rows;
+  if ((cache_info->columns == nexus_info->region.width) &&
+      (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
+    {
+      length=number_pixels;
+      rows=1UL;
+    }
+  q=nexus_info->indexes;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register IndexPacket
+        *__restrict p;
+
+      /*
+        Read indexes from memory.
+      */
+      p=cache_info->indexes+offset;
+      for (y=0; y < (long) rows; y++)
+      {
+        (void) CopyMagickMemory(q,p,(size_t) length);
+        p+=cache_info->columns;
+        q+=nexus_info->region.width;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Read indexes from disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+      for (y=0; y < (long) rows; y++)
+      {
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
+          sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
+        if ((MagickSizeType) count < length)
+          break;
+        offset+=cache_info->columns;
+        q+=nexus_info->region.width;
+      }
+      if (y < (long) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
+      cache_info->filename,nexus_info->region.width,nexus_info->region.height,
+      nexus_info->region.x,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
+    length,
+    number_pixels;
+
+  register long
+    y;
+
+  register PixelPacket
+    *__restrict q;
+
+  unsigned long
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  if (IsNexusInCore(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*sizeof(PixelPacket);
+  rows=nexus_info->region.height;
+  number_pixels=length*rows;
+  if ((cache_info->columns == nexus_info->region.width) &&
+      (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
+    {
+      length=number_pixels;
+      rows=1UL;
+    }
+  q=nexus_info->pixels;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register PixelPacket
+        *__restrict p;
+
+      /*
+        Read pixels from memory.
+      */
+      p=cache_info->pixels+offset;
+      for (y=0; y < (long) rows; y++)
+      {
+        (void) CopyMagickMemory(q,p,(size_t) length);
+        p+=cache_info->columns;
+        q+=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);
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
+          sizeof(*q),length,(unsigned char *) q);
+        if ((MagickSizeType) count < length)
+          break;
+        offset+=cache_info->columns;
+        q+=nexus_info->region.width;
+      }
+      if (y < (long) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
+      cache_info->filename,nexus_info->region.width,nexus_info->region.height,
+      nexus_info->region.x,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);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  (void) LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count++;
+  (void) 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_indexes_from_handler !=
+      (GetVirtualIndexesFromHandler) NULL)
+    cache_info->methods.get_virtual_indexes_from_handler=
+      cache_methods->get_virtual_indexes_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_indexes_from_handler !=
+      (GetAuthenticIndexesFromHandler) NULL)
+    cache_info->methods.get_authentic_indexes_from_handler=
+      cache_methods->get_authentic_indexes_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:
+%
+%      PixelPacket 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 PixelPacket *SetPixelCacheNexusPixels(const Image *image,
+  const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->type == UndefinedCache)
+    return((PixelPacket *) NULL);
+  nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
+  nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
+  nexus_info->region.x=region->x;
+  nexus_info->region.y=region->y;
+  if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
+      (image->mask == (Image *) NULL))
+    {
+      offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+        nexus_info->region.x;
+      length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
+        nexus_info->region.width-1;
+      number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+      if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
+        {
+          long
+            x,
+            y;
+
+          x=nexus_info->region.x+nexus_info->region.width;
+          y=nexus_info->region.y+nexus_info->region.height;
+          if ((nexus_info->region.x >= 0) &&
+              (x <= (long) cache_info->columns) &&
+              (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
+            if ((nexus_info->region.height == 1UL) ||
+                ((nexus_info->region.x == 0) &&
+                ((nexus_info->region.width % cache_info->columns) == 0)))
+              {
+                /*
+                  Pixels are accessed directly from memory.
+                */
+                nexus_info->pixels=cache_info->pixels+offset;
+                nexus_info->indexes=(IndexPacket *) NULL;
+                if (cache_info->active_index_channel != MagickFalse)
+                  nexus_info->indexes=cache_info->indexes+offset;
+                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*sizeof(PixelPacket);
+  if (cache_info->active_index_channel != MagickFalse)
+    length+=number_pixels*sizeof(IndexPacket);
+  if (nexus_info->cache == (PixelPacket *) NULL)
+    {
+      nexus_info->length=length;
+      status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
+      if (status == MagickFalse)
+        return((PixelPacket *) NULL);
+    }
+  else
+    if (nexus_info->length != length)
+      {
+        RelinquishCacheNexusPixels(nexus_info);
+        nexus_info->length=length;
+        status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
+        if (status == MagickFalse)
+          return((PixelPacket *) NULL);
+      }
+  nexus_info->pixels=nexus_info->cache;
+  nexus_info->indexes=(IndexPacket *) NULL;
+  if (cache_info->active_index_channel != MagickFalse)
+    nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
+  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->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->cache == (Cache) NULL)
+    ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  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 (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  assert(cache_info->signature == MagickSignature);
+  status=WritePixelCachePixels(cache_info,nexus_info,exception);
+  if ((cache_info->active_index_channel != MagickFalse) &&
+      (WritePixelCacheIndexes(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;
+
+  long
+    id;
+
+  MagickBooleanType
+    status;
+
+  cache_info=(CacheInfo *) image->cache;
+  id=GetOpenMPThreadId();
+  assert(id < (long) 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;
+
+  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);
+  if (cache_info->methods.sync_authentic_pixels_handler ==
+      (SyncAuthenticPixelsHandler) NULL)
+    return(MagickFalse);
+  return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   W r i t e P i x e l C a c h e I n d e x e s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WritePixelCacheIndexes() writes the colormap indexes to the specified
+%  region of the pixel cache.
+%
+%  The format of the WritePixelCacheIndexes() method is:
+%
+%      MagickBooleanType WritePixelCacheIndexes(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 colormap indexes.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  register const IndexPacket
+    *__restrict p;
+
+  register long
+    y;
+
+  unsigned long
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  if (cache_info->active_index_channel == MagickFalse)
+    return(MagickFalse);
+  if (IsNexusInCore(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*sizeof(IndexPacket);
+  rows=nexus_info->region.height;
+  number_pixels=(MagickSizeType) length*rows;
+  if ((cache_info->columns == nexus_info->region.width) &&
+      (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
+    {
+      length=number_pixels;
+      rows=1UL;
+    }
+  p=nexus_info->indexes;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register IndexPacket
+        *__restrict q;
+
+      /*
+        Write indexes to memory.
+      */
+      q=cache_info->indexes+offset;
+      for (y=0; y < (long) rows; y++)
+      {
+        (void) CopyMagickMemory(q,p,(size_t) length);
+        p+=nexus_info->region.width;
+        q+=cache_info->columns;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Write indexes to disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+      for (y=0; y < (long) rows; y++)
+      {
+        count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
+          sizeof(PixelPacket)+offset*sizeof(*p),length,
+          (const unsigned char *) p);
+        if ((MagickSizeType) count < length)
+          break;
+        p+=nexus_info->region.width;
+        offset+=cache_info->columns;
+      }
+      if (y < (long) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
+      cache_info->filename,nexus_info->region.width,nexus_info->region.height,
+      nexus_info->region.x,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
+    length,
+    number_pixels;
+
+  register long
+    y;
+
+  register const PixelPacket
+    *__restrict p;
+
+  unsigned long
+    rows;
+
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  if (IsNexusInCore(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*sizeof(PixelPacket);
+  rows=nexus_info->region.height;
+  number_pixels=length*rows;
+  if ((cache_info->columns == nexus_info->region.width) &&
+      (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
+    {
+      length=number_pixels;
+      rows=1UL;
+    }
+  p=nexus_info->pixels;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Write pixels to memory.
+      */
+      q=cache_info->pixels+offset;
+      for (y=0; y < (long) rows; y++)
+      {
+        (void) CopyMagickMemory(q,p,(size_t) length);
+        p+=nexus_info->region.width;
+        q+=cache_info->columns;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Write pixels to disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
+          sizeof(*p),length,(const unsigned char *) p);
+        if ((MagickSizeType) count < length)
+          break;
+        p+=nexus_info->region.width;
+        offset+=cache_info->columns;
+      }
+      if (y < (long) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
+      cache_info->filename,nexus_info->region.width,nexus_info->region.height,
+      nexus_info->region.x,nexus_info->region.y);
+  return(MagickTrue);
+}
diff --git a/magick/cache.h b/magick/cache.h
new file mode 100644
index 0000000..1fa119a
--- /dev/null
+++ b/magick/cache.h
@@ -0,0 +1,72 @@
+/*
+  Copyright 1999-2009 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 "magick/blob.h"
+
+extern MagickExport const IndexPacket
+  *GetVirtualIndexQueue(const Image *);
+
+extern MagickExport const PixelPacket
+  *GetVirtualPixels(const Image *,const long,const long,const unsigned long,
+    const unsigned long,ExceptionInfo *),
+  *GetVirtualPixelQueue(const Image *);
+
+extern MagickExport IndexPacket
+  *GetAuthenticIndexQueue(const Image *);
+
+extern MagickExport MagickBooleanType
+  GetOneVirtualMagickPixel(const Image *,const long,const long,
+    MagickPixelPacket *,ExceptionInfo *),
+  GetOneVirtualPixel(const Image *,const long,const long,PixelPacket *,
+    ExceptionInfo *),
+  GetOneVirtualMethodPixel(const Image *,const VirtualPixelMethod,const long,
+    const long,PixelPacket *,ExceptionInfo *),
+  GetOneAuthenticPixel(Image *,const long,const long,PixelPacket *,
+    ExceptionInfo *),
+  PersistPixelCache(Image *,const char *,const MagickBooleanType,
+    MagickOffsetType *,ExceptionInfo *),
+  SyncAuthenticPixels(Image *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetImageExtent(const Image *);
+
+extern MagickExport PixelPacket
+  *GetAuthenticPixels(Image *,const long,const long,const unsigned long,
+    const unsigned long,ExceptionInfo *),
+  *GetAuthenticPixelQueue(const Image *),
+  *QueueAuthenticPixels(Image *,const long,const long,const unsigned long,
+    const unsigned long,ExceptionInfo *);
+
+extern MagickExport VirtualPixelMethod
+  GetPixelCacheVirtualMethod(const Image *),
+  SetPixelCacheVirtualMethod(const Image *,const VirtualPixelMethod);
+
+extern MagickExport void
+  DestroyPixelCacheResources(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/cipher.c b/magick/cipher.c
new file mode 100644
index 0000000..26d5db1
--- /dev/null
+++ b/magick/cipher.c
@@ -0,0 +1,1157 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                   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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/cipher.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/property.h"
+#include "magick/quantum-private.h"
+#include "magick/registry.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/splay-tree.h"
+#include "magick/statistic.h"
+#include "magick/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;
+
+  long
+    rounds,
+    timestamp;
+
+  unsigned long
+    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=(long) 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 long
+    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 long
+    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;
+
+  const unsigned char
+    *digest;
+
+  IndexPacket
+    *indexes;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  SignatureInfo
+    *signature_info;
+
+  register unsigned char
+    *p;
+
+  size_t
+    length;
+
+  StringInfo
+    *key,
+    *nonce;
+
+  unsigned char
+    input_block[AESBlocksize],
+    output_block[AESBlocksize],
+    *pixels;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    p=pixels;
+    for (x=0; x < (long) 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,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 == (long) 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;
+
+  char
+    *signature;
+
+  const unsigned char
+    *digest;
+
+  IndexPacket
+    *indexes;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  register unsigned char
+    *p;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    length;
+
+  StringInfo
+    *key,
+    *nonce;
+
+  unsigned char
+    input_block[AESBlocksize],
+    output_block[AESBlocksize],
+    *pixels;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    p=pixels;
+    for (x=0; x < (long) 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,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 == (long) 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)
+{
+  long
+    bytes,
+    n;
+
+  register long
+    i;
+
+  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/magick/cipher.h b/magick/cipher.h
new file mode 100644
index 0000000..1a9152b
--- /dev/null
+++ b/magick/cipher.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2009 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/magick/client.c b/magick/client.c
new file mode 100644
index 0000000..50b47cd
--- /dev/null
+++ b/magick/client.c
@@ -0,0 +1,162 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/client.h"
+#include "magick/string_.h"
+
+/*
+  Static declaractions.
+*/
+static char
+  client_name[MaxTextExtent] = "ImageMagick",
+  client_path[MaxTextExtent] = "";
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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(client_name);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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(client_path);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 client_name: SetClientName() returns the current client name.
+%
+%    o name: Specifies the new client name.
+%
+*/
+MagickExport const char *SetClientName(const char *name)
+{
+  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 client_path: Method SetClientPath returns the current client path.
+%
+%    o path: Specifies the new client path.
+%
+%
+*/
+MagickExport const char *SetClientPath(const char *path)
+{
+  if ((path != (char *) NULL) && (*path != '\0'))
+    (void) CopyMagickString(client_path,path,MaxTextExtent);
+  return(client_path);
+}
diff --git a/magick/client.h b/magick/client.h
new file mode 100644
index 0000000..330e1f4
--- /dev/null
+++ b/magick/client.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2009 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/magick/coder.c b/magick/coder.c
new file mode 100644
index 0000000..70f77f9
--- /dev/null
+++ b/magick/coder.c
@@ -0,0 +1,852 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/coder.h"
+#include "magick/configure.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/splay-tree.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MagickCoderFilename  "coder.xml"
+
+/*
+  Declare coder map.
+*/
+static const char
+  *CoderMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<codermap>"
+    "  <coder magick=\"8BIM\" name=\"META\" />"
+    "  <coder magick=\"8BIMTEXT\" name=\"META\" />"
+    "  <coder magick=\"8BIMWTEXT\" name=\"META\" />"
+    "  <coder magick=\"A\" name=\"RAW\" />"
+    "  <coder magick=\"AI\" name=\"PDF\" />"
+    "  <coder magick=\"AFM\" name=\"TTF\" />"
+    "  <coder magick=\"APP1JPEG\" name=\"META\" />"
+    "  <coder magick=\"APP1\" name=\"META\" />"
+    "  <coder magick=\"ARW\" name=\"DNG\" />"
+    "  <coder magick=\"BIE\" name=\"JBIG\" />"
+    "  <coder magick=\"BMP2\" name=\"BMP\" />"
+    "  <coder magick=\"BMP3\" name=\"BMP\" />"
+    "  <coder magick=\"B\" name=\"GRAY\" />"
+    "  <coder magick=\"BRF\" name=\"BRAILLE\" />"
+    "  <coder magick=\"CMYKA\" name=\"CMYK\" />"
+    "  <coder magick=\"C\" name=\"GRAY\" />"
+    "  <coder magick=\"CR2\" name=\"DNG\" />"
+    "  <coder magick=\"CRW\" name=\"DNG\" />"
+    "  <coder magick=\"CUR\" name=\"ICON\" />"
+    "  <coder magick=\"DCR\" name=\"DNG\" />"
+    "  <coder magick=\"DCX\" name=\"PCX\" />"
+    "  <coder magick=\"DFONT\" name=\"TTF\" />"
+    "  <coder magick=\"EMF\" name=\"EMF\" />"
+    "  <coder magick=\"EPDF\" name=\"PDF\" />"
+    "  <coder magick=\"EPI\" name=\"PS\" />"
+    "  <coder magick=\"EPS2\" name=\"PS2\" />"
+    "  <coder magick=\"EPS3\" name=\"PS3\" />"
+    "  <coder magick=\"EPSF\" name=\"PS\" />"
+    "  <coder magick=\"EPSI\" name=\"PS\" />"
+    "  <coder magick=\"EPS\" name=\"PS\" />"
+    "  <coder magick=\"EPT2\" name=\"EPT\" />"
+    "  <coder magick=\"EPT3\" name=\"EPT\" />"
+    "  <coder magick=\"EXIF\" name=\"META\" />"
+    "  <coder magick=\"FILE\" name=\"URL\" />"
+    "  <coder magick=\"FRACTAL\" name=\"PLASMA\" />"
+    "  <coder magick=\"FTP\" name=\"URL\" />"
+    "  <coder magick=\"FTS\" name=\"FITS\" />"
+    "  <coder magick=\"G3\" name=\"FAX\" />"
+    "  <coder magick=\"GIF87\" name=\"GIF\" />"
+    "  <coder magick=\"G\" name=\"GRAY\" />"
+    "  <coder magick=\"GRANITE\" name=\"MAGICK\" />"
+    "  <coder magick=\"H\" name=\"MAGICK\" />"
+    "  <coder magick=\"HTM\" name=\"HTML\" />"
+    "  <coder magick=\"HTTP\" name=\"URL\" />"
+    "  <coder magick=\"ICB\" name=\"TGA\" />"
+    "  <coder magick=\"ICC\" name=\"META\" />"
+    "  <coder magick=\"ICM\" name=\"META\" />"
+    "  <coder magick=\"ICO\" name=\"ICON\" />"
+    "  <coder magick=\"IMPLICIT\" name=\"***\" />"
+    "  <coder magick=\"IPTC\" name=\"META\" />"
+    "  <coder magick=\"IPTCTEXT\" name=\"META\" />"
+    "  <coder magick=\"IPTCWTEXT\" name=\"META\" />"
+    "  <coder magick=\"ISOBRL\" name=\"BRAILLE\" />"
+    "  <coder magick=\"JBG\" name=\"JBIG\" />"
+    "  <coder magick=\"JNG\" name=\"PNG\" />"
+    "  <coder magick=\"JPC\" name=\"JP2\" />"
+    "  <coder magick=\"JPG\" name=\"JPEG\" />"
+    "  <coder magick=\"JPX\" name=\"JP2\" />"
+    "  <coder magick=\"K\" name=\"GRAY\" />"
+    "  <coder magick=\"LOGO\" name=\"MAGICK\" />"
+    "  <coder magick=\"M2V\" name=\"MPEG\" />"
+    "  <coder magick=\"M4V\" name=\"MPEG\" />"
+    "  <coder magick=\"M\" name=\"GRAY\" />"
+    "  <coder magick=\"MNG\" name=\"PNG\" />"
+    "  <coder magick=\"MOV\" name=\"MPEG\" />"
+    "  <coder magick=\"MPG\" name=\"MPEG\" />"
+    "  <coder magick=\"MP4\" name=\"MPEG\" />"
+    "  <coder magick=\"MPRI\" name=\"MPR\" />"
+    "  <coder magick=\"MRW\" name=\"DNG\" />"
+    "  <coder magick=\"MSVG\" name=\"SVG\" />"
+    "  <coder magick=\"NEF\" name=\"DNG\" />"
+    "  <coder magick=\"NETSCAPE\" name=\"MAGICK\" />"
+    "  <coder magick=\"O\" name=\"GRAY\" />"
+    "  <coder magick=\"ORF\" name=\"DNG\" />"
+    "  <coder magick=\"OTF\" name=\"TTF\" />"
+    "  <coder magick=\"P7\" name=\"PNM\" />"
+    "  <coder magick=\"PAL\" name=\"UYVY\" />"
+    "  <coder magick=\"PAM\" name=\"PNM\" />"
+    "  <coder magick=\"PBM\" name=\"PNM\" />"
+    "  <coder magick=\"PCDS\" name=\"PCD\" />"
+    "  <coder magick=\"PCT\" name=\"PICT\" />"
+    "  <coder magick=\"PDFA\" name=\"PDF\" />"
+    "  <coder magick=\"PEF\" name=\"DNG\" />"
+    "  <coder magick=\"PFA\" name=\"TTF\" />"
+    "  <coder magick=\"PFB\" name=\"TTF\" />"
+    "  <coder magick=\"PFM\" name=\"PNM\" />"
+    "  <coder magick=\"PGM\" name=\"PNM\" />"
+    "  <coder magick=\"PGX\" name=\"JP2\" />"
+    "  <coder magick=\"PICON\" name=\"XPM\" />"
+    "  <coder magick=\"PJPEG\" name=\"JPEG\" />"
+    "  <coder magick=\"PM\" name=\"XPM\" />"
+    "  <coder magick=\"PNG24\" name=\"PNG\" />"
+    "  <coder magick=\"PNG32\" name=\"PNG\" />"
+    "  <coder magick=\"PNG8\" name=\"PNG\" />"
+    "  <coder magick=\"PPM\" name=\"PNM\" />"
+    "  <coder magick=\"PTIF\" name=\"TIFF\" />"
+    "  <coder magick=\"RADIAL-GRADIENT\" name=\"GRADIENT\" />"
+    "  <coder magick=\"RAF\" name=\"DNG\" />"
+    "  <coder magick=\"RAS\" name=\"SUN\" />"
+    "  <coder magick=\"RGBA\" name=\"RGB\" />"
+    "  <coder magick=\"RGBO\" name=\"RGB\" />"
+    "  <coder magick=\"R\" name=\"GRAY\" />"
+    "  <coder magick=\"ROSE\" name=\"MAGICK\" />"
+    "  <coder magick=\"SHTML\" name=\"HTML\" />"
+    "  <coder magick=\"SVGZ\" name=\"SVG\" />"
+    "  <coder magick=\"TEXT\" name=\"TXT\" />"
+    "  <coder magick=\"TIFF64\" name=\"TIFF\" />"
+    "  <coder magick=\"TIF\" name=\"TIFF\" />"
+    "  <coder magick=\"TTC\" name=\"TTF\" />"
+    "  <coder magick=\"UBRL\" name=\"BRAILLE\" />"
+    "  <coder magick=\"VDA\" name=\"TGA\" />"
+    "  <coder magick=\"VST\" name=\"TGA\" />"
+    "  <coder magick=\"WMFWIN32\" name=\"EMF\" />"
+    "  <coder magick=\"WMV\" name=\"MPEG\" />"
+    "  <coder magick=\"X3F\" name=\"DNG\" />"
+    "  <coder magick=\"XTRNARRAY\" name=\"XTRN\" />"
+    "  <coder magick=\"XTRNBLOB\" name=\"XTRN\" />"
+    "  <coder magick=\"XTRNBSTR\" name=\"XTRN\" />"
+    "  <coder magick=\"XTRNFILE\" name=\"XTRN\" />"
+    "  <coder magick=\"XTRNIMAGE\" name=\"XTRN\" />"
+    "  <coder magick=\"XTRNSTREAM\" name=\"XTRN\" />"
+    "  <coder magick=\"XV\" name=\"VIFF\" />"
+    "  <coder magick=\"Y\" name=\"GRAY\" />"
+    "  <coder magick=\"YCbCrA\" name=\"YCbCr\" />"
+    "</codermap>";
+
+/*
+  Static declarations.
+*/
+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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C o d e r L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCoderList() deallocates memory associated with the font list.
+%
+%  The format of the DestroyCoderList method is:
+%
+%      DestroyCoderList(void)
+%
+*/
+MagickExport void DestroyCoderList(void)
+{
+  AcquireSemaphoreInfo(&coder_semaphore);
+  if (coder_list != (SplayTreeInfo *) NULL)
+    coder_list=DestroySplayTree(coder_list);
+  instantiate_coder=MagickFalse;
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_coders,ExceptionInfo *exception)
+{
+  const CoderInfo
+    **coder_map;
+
+  register const CoderInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate coder list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_coders != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(coder_semaphore);
+  qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
+  coder_map[i]=(CoderInfo *) NULL;
+  *number_coders=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_coders,ExceptionInfo *exception)
+{
+  char
+    **coder_map;
+
+  register const CoderInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate coder list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_coders != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(coder_semaphore);
+  qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
+  coder_map[i]=(char *) NULL;
+  *number_coders=(unsigned long) 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))
+    {
+      AcquireSemaphoreInfo(&coder_semaphore);
+      if ((coder_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_coder == MagickFalse))
+        {
+          (void) LoadCoderLists(MagickCoderFilename,exception);
+          instantiate_coder=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_coders;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",coder_info[i]->path);
+        (void) fprintf(file,"Magick      Coder\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=coder_info[i]->path;
+    (void) fprintf(file,"%s",coder_info[i]->magick);
+    for (j=(long) strlen(coder_info[i]->magick); j <= 11; j++)
+      (void) fprintf(file," ");
+    if (coder_info[i]->name != (char *) NULL)
+      (void) fprintf(file,"%s",coder_info[i]->name);
+    (void) fprintf(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 unsigned long 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->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 unsigned long 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->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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadCoderList(CoderMap,"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|=LoadCoderList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((coder_list == (SplayTreeInfo *) NULL) || 
+      (GetNumberOfNodesInSplayTree(coder_list) == 0))
+    status|=LoadCoderList(CoderMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
diff --git a/magick/coder.h b/magick/coder.h
new file mode 100644
index 0000000..f4b81bd
--- /dev/null
+++ b/magick/coder.h
@@ -0,0 +1,60 @@
+/*
+  Copyright 1999-2009 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
+    stealth;
+                                                                                
+  struct _CoderInfo
+    *previous,
+    *next;  /* deprecated, use GetCoderInfoList() */
+
+  unsigned long
+    signature;
+} CoderInfo;
+
+extern MagickExport char
+  **GetCoderList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const CoderInfo
+  *GetCoderInfo(const char *,ExceptionInfo *),
+  **GetCoderInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListCoderInfo(FILE *,ExceptionInfo *);
+
+MagickExport void
+  DestroyCoderList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/color-private.h b/magick/color-private.h
new file mode 100644
index 0000000..d7bac5d
--- /dev/null
+++ b/magick/color-private.h
@@ -0,0 +1,155 @@
+/*
+  Copyright 1999-2009 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
+
+#include <magick/image.h>
+#include <magick/color.h>
+#include <magick/exception-private.h>
+
+static inline MagickBooleanType IsColorEqual(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 IndexPacket ConstrainColormapIndex(Image *image,
+  const unsigned long index)
+{
+  if (index < image->colors)
+    return((IndexPacket) index);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+  return((IndexPacket) 0);
+}
+
+static inline MagickBooleanType IsGray(const PixelPacket *pixel)
+{
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsMagickColorEqual(const MagickPixelPacket *p,
+  const MagickPixelPacket *q)
+{
+  if ((p->matte != MagickFalse) && (q->matte == MagickFalse) &&
+      (p->opacity != OpaqueOpacity))
+    return(MagickFalse);
+  if ((q->matte != MagickFalse) && (p->matte == MagickFalse) &&
+      (q->opacity != OpaqueOpacity))
+    return(MagickFalse);
+  if ((p->matte != MagickFalse) && (q->matte != MagickFalse))
+    {
+      if (p->opacity != q->opacity)
+        return(MagickFalse);
+      if (p->opacity == TransparentOpacity)
+        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->index != q->index))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static inline MagickBooleanType IsMagickGray(const MagickPixelPacket *pixel)
+{
+  if (pixel->colorspace != RGBColorspace)
+    return(MagickFalse);
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline MagickRealType MagickPixelIntensity(
+  const MagickPixelPacket *pixel)
+{
+  MagickRealType
+    intensity;
+
+  intensity=0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue;
+  return(intensity);
+}
+
+static inline Quantum MagickPixelIntensityToQuantum(
+  const MagickPixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue+0.5));
+#else
+  return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue));
+#endif
+}
+
+static inline MagickRealType MagickPixelLuminance(
+  const MagickPixelPacket *pixel)
+{
+  MagickRealType
+    luminance;
+
+  luminance=0.21267*pixel->red+0.71516*pixel->green+0.07217*pixel->blue;
+  return(luminance);
+}
+
+static inline MagickRealType PixelIntensity(const PixelPacket *pixel)
+{
+  MagickRealType
+    intensity;
+
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return((MagickRealType) pixel->red);
+  intensity=(MagickRealType) (0.299*pixel->red+0.587*pixel->green+0.114*
+    pixel->blue);
+  return(intensity);
+}
+
+static inline Quantum PixelIntensityToQuantum(const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(pixel->red);
+#if (MAGICKCORE_QUANTUM_DEPTH <= 16)
+  return((Quantum) ((306U*(unsigned int) pixel->red+
+    601U*(unsigned int) pixel->green+117U*(unsigned int) pixel->blue) >> 10U));
+#else
+  return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue+0.5));
+#endif
+#else
+  if ((fabs(pixel->red-pixel->green) <= MagickEpsilon) &&
+      (fabs(pixel->green-pixel->blue) <= MagickEpsilon))
+    return((Quantum) pixel->red);
+  return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue));
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/color.c b/magick/color.c
new file mode 100644
index 0000000..e309099
--- /dev/null
+++ b/magick/color.c
@@ -0,0 +1,3528 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                       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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/cache-view.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ColorFilename  "colors.xml"
+#define MaxTreeDepth  8
+#define NodesInAList  1536
+
+/*
+  Declare color map.
+*/
+static const char
+  *ColorMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<colormap>"
+    "  <color name=\"none\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
+    "  <color name=\"black\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"red\" color=\"rgb(255,0,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"magenta\" color=\"rgb(255,0,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"green\" color=\"rgb(0,128,0)\" compliance=\"SVG\" />"
+    "  <color name=\"cyan\" color=\"rgb(0,255,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"blue\" color=\"rgb(0,0,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"yellow\" color=\"rgb(255,255,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"white\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"AliceBlue\" color=\"rgb(240,248,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"AntiqueWhite\" color=\"rgb(250,235,215)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"aqua\" color=\"rgb(0,255,255)\" compliance=\"SVG\" />"
+    "  <color name=\"aquamarine\" color=\"rgb(127,255,212)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"azure\" color=\"rgb(240,255,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"beige\" color=\"rgb(245,245,220)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"bisque\" color=\"rgb(255,228,196)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"BlanchedAlmond\" color=\"rgb(255,235,205)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"BlueViolet\" color=\"rgb(138,43,226)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"brown\" color=\"rgb(165,42,42)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"burlywood\" color=\"rgb(222,184,135)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"CadetBlue\" color=\"rgb(95,158,160)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"chartreuse\" color=\"rgb(127,255,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"chocolate\" color=\"rgb(210,105,30)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"coral\" color=\"rgb(255,127,80)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"CornflowerBlue\" color=\"rgb(100,149,237)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"cornsilk\" color=\"rgb(255,248,220)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"crimson\" color=\"rgb(220,20,60)\" compliance=\"SVG\" />"
+    "  <color name=\"DarkBlue\" color=\"rgb(0,0,139)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkCyan\" color=\"rgb(0,139,139)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkGoldenrod\" color=\"rgb(184,134,11)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkGray\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkGreen\" color=\"rgb(0,100,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkGrey\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkKhaki\" color=\"rgb(189,183,107)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkMagenta\" color=\"rgb(139,0,139)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkOliveGreen\" color=\"rgb(85,107,47)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkOrange\" color=\"rgb(255,140,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkOrchid\" color=\"rgb(153,50,204)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkRed\" color=\"rgb(139,0,0)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkSalmon\" color=\"rgb(233,150,122)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkSeaGreen\" color=\"rgb(143,188,143)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkSlateBlue\" color=\"rgb(72,61,139)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkSlateGray\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkSlateGrey\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DarkTurquoise\" color=\"rgb(0,206,209)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DarkViolet\" color=\"rgb(148,0,211)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DeepPink\" color=\"rgb(255,20,147)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DeepSkyBlue\" color=\"rgb(0,191,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DimGray\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"DimGrey\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"DodgerBlue\" color=\"rgb(30,144,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"firebrick\" color=\"rgb(178,34,34)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"FloralWhite\" color=\"rgb(255,250,240)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"ForestGreen\" color=\"rgb(34,139,34)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"fractal\" color=\"rgb(128,128,128)\" compliance=\"SVG\" />"
+    "  <color name=\"fuchsia\" color=\"rgb(255,0,255)\" compliance=\"SVG\" />"
+    "  <color name=\"gainsboro\" color=\"rgb(220,220,220)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"GhostWhite\" color=\"rgb(248,248,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"gold\" color=\"rgb(255,215,0)\" compliance=\"X11, XPM\" />"
+    "  <color name=\"goldenrod\" color=\"rgb(218,165,32)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"gray\" color=\"rgb(126,126,126)\" compliance=\"SVG\" />"
+    "  <color name=\"gray74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"gray100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey\" color=\"rgb(190,190,190)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey0\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey1\" color=\"rgb(3,3,3)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey10\" color=\"rgb(26,26,26)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey11\" color=\"rgb(28,28,28)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey12\" color=\"rgb(31,31,31)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey13\" color=\"rgb(33,33,33)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey14\" color=\"rgb(36,36,36)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey15\" color=\"rgb(38,38,38)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey16\" color=\"rgb(41,41,41)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey17\" color=\"rgb(43,43,43)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey18\" color=\"rgb(45,45,45)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey19\" color=\"rgb(48,48,48)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey2\" color=\"rgb(5,5,5)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey20\" color=\"rgb(51,51,51)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey21\" color=\"rgb(54,54,54)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey22\" color=\"rgb(56,56,56)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey23\" color=\"rgb(59,59,59)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey24\" color=\"rgb(61,61,61)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey25\" color=\"rgb(64,64,64)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey26\" color=\"rgb(66,66,66)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey27\" color=\"rgb(69,69,69)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey28\" color=\"rgb(71,71,71)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey29\" color=\"rgb(74,74,74)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey3\" color=\"rgb(8,8,8)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey30\" color=\"rgb(77,77,77)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey31\" color=\"rgb(79,79,79)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey32\" color=\"rgb(82,82,82)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey33\" color=\"rgb(84,84,84)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey34\" color=\"rgb(87,87,87)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey35\" color=\"rgb(89,89,89)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey36\" color=\"rgb(92,92,92)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey37\" color=\"rgb(94,94,94)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey38\" color=\"rgb(97,97,97)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey39\" color=\"rgb(99,99,99)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey4\" color=\"rgb(10,10,10)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey40\" color=\"rgb(102,102,102)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey41\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey42\" color=\"rgb(107,107,107)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey43\" color=\"rgb(110,110,110)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey44\" color=\"rgb(112,112,112)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey45\" color=\"rgb(115,115,115)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey45\" color=\"rgb(117,117,117)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey47\" color=\"rgb(120,120,120)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey48\" color=\"rgb(122,122,122)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey49\" color=\"rgb(125,125,125)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey5\" color=\"rgb(13,13,13)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey50\" color=\"rgb(50%,50%,50%)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey51\" color=\"rgb(130,130,130)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey52\" color=\"rgb(133,133,133)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey53\" color=\"rgb(135,135,135)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey54\" color=\"rgb(138,138,138)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey55\" color=\"rgb(140,140,140)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey56\" color=\"rgb(143,143,143)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey57\" color=\"rgb(145,145,145)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey58\" color=\"rgb(148,148,148)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey59\" color=\"rgb(150,150,150)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey6\" color=\"rgb(15,15,15)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey60\" color=\"rgb(153,153,153)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey61\" color=\"rgb(156,156,156)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey62\" color=\"rgb(158,158,158)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey63\" color=\"rgb(161,161,161)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey64\" color=\"rgb(163,163,163)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey65\" color=\"rgb(166,166,166)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey66\" color=\"rgb(168,168,168)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey67\" color=\"rgb(171,171,171)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey68\" color=\"rgb(173,173,173)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey69\" color=\"rgb(176,176,176)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey7\" color=\"rgb(18,18,18)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey70\" color=\"rgb(179,179,179)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey71\" color=\"rgb(181,181,181)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey72\" color=\"rgb(184,184,184)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey73\" color=\"rgb(186,186,186)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey75\" color=\"rgb(191,191,191)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey76\" color=\"rgb(194,194,194)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey77\" color=\"rgb(196,196,196)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey78\" color=\"rgb(199,199,199)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey79\" color=\"rgb(201,201,201)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey8\" color=\"rgb(20,20,20)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey80\" color=\"rgb(204,204,204)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey81\" color=\"rgb(207,207,207)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey82\" color=\"rgb(209,209,209)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey83\" color=\"rgb(212,212,212)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey84\" color=\"rgb(214,214,214)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey85\" color=\"rgb(217,217,217)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey86\" color=\"rgb(219,219,219)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey87\" color=\"rgb(222,222,222)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey88\" color=\"rgb(224,224,224)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey89\" color=\"rgb(227,227,227)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey9\" color=\"rgb(23,23,23)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey90\" color=\"rgb(229,229,229)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey91\" color=\"rgb(232,232,232)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey92\" color=\"rgb(235,235,235)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey93\" color=\"rgb(237,237,237)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey94\" color=\"rgb(240,240,240)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey95\" color=\"rgb(242,242,242)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey96\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey97\" color=\"rgb(247,247,247)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey98\" color=\"rgb(250,250,250)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"grey99\" color=\"rgb(252,252,252)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"honeydew\" color=\"rgb(240,255,240)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"HotPink\" color=\"rgb(255,105,180)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"IndianRed\" color=\"rgb(205,92,92)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"indigo\" color=\"rgb(75,0,130)\" compliance=\"SVG\" />"
+    "  <color name=\"ivory\" color=\"rgb(255,255,240)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"khaki\" color=\"rgb(240,230,140)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"lavender\" color=\"rgb(230,230,250)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LavenderBlush\" color=\"rgb(255,240,245)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LawnGreen\" color=\"rgb(124,252,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LemonChiffon\" color=\"rgb(255,250,205)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightBlue\" color=\"rgb(173,216,230)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightCoral\" color=\"rgb(240,128,128)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightCyan\" color=\"rgb(224,255,255)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightGoldenrodYellow\" color=\"rgb(250,250,210)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightGray\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightGreen\" color=\"rgb(144,238,144)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"LightGrey\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"LightPink\" color=\"rgb(255,182,193)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightSalmon\" color=\"rgb(255,160,122)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightSeaGreen\" color=\"rgb(32,178,170)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightSkyBlue\" color=\"rgb(135,206,250)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightSlateGray\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightSlateGrey\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"LightSteelBlue\" color=\"rgb(176,196,222)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"LightYellow\" color=\"rgb(255,255,224)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"lime\" color=\"rgb(0,255,0)\" compliance=\"SVG\" />"
+    "  <color name=\"LimeGreen\" color=\"rgb(50,205,50)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"linen\" color=\"rgb(250,240,230)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"maroon\" color=\"rgb(128,0,0)\" compliance=\"SVG\" />"
+    "  <color name=\"MediumAquamarine\" color=\"rgb(102,205,170)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumBlue\" color=\"rgb(0,0,205)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumOrchid\" color=\"rgb(186,85,211)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumPurple\" color=\"rgb(147,112,219)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumSeaGreen\" color=\"rgb(60,179,113)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumSlateBlue\" color=\"rgb(123,104,238)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumSpringGreen\" color=\"rgb(0,250,154)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumTurquoise\" color=\"rgb(72,209,204)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MediumVioletRed\" color=\"rgb(199,21,133)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MidnightBlue\" color=\"rgb(25,25,112)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MintCream\" color=\"rgb(245,255,250)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"MistyRose\" color=\"rgb(255,228,225)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"moccasin\" color=\"rgb(255,228,181)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"NavajoWhite\" color=\"rgb(255,222,173)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"navy\" color=\"rgb(0,0,128)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"matte\" color=\"rgb(0,0,0,0)\" compliance=\"SVG\" />"
+    "  <color name=\"OldLace\" color=\"rgb(253,245,230)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"olive\" color=\"rgb(128,128,0)\" compliance=\"SVG\" />"
+    "  <color name=\"OliveDrab\" color=\"rgb(107,142,35)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"opaque\" color=\"rgb(0,0,0)\" compliance=\"SVG\" />"
+    "  <color name=\"orange\" color=\"rgb(255,165,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"OrangeRed\" color=\"rgb(255,69,0)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"orchid\" color=\"rgb(218,112,214)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PaleGoldenrod\" color=\"rgb(238,232,170)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PaleGreen\" color=\"rgb(152,251,152)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PaleTurquoise\" color=\"rgb(175,238,238)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PaleVioletRed\" color=\"rgb(219,112,147)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PapayaWhip\" color=\"rgb(255,239,213)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PeachPuff\" color=\"rgb(255,218,185)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"peru\" color=\"rgb(205,133,63)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"pink\" color=\"rgb(255,192,203)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"plum\" color=\"rgb(221,160,221)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"PowderBlue\" color=\"rgb(176,224,230)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"purple\" color=\"rgb(128,0,128)\" compliance=\"SVG\" />"
+    "  <color name=\"RosyBrown\" color=\"rgb(188,143,143)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"RoyalBlue\" color=\"rgb(65,105,225)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SaddleBrown\" color=\"rgb(139,69,19)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"salmon\" color=\"rgb(250,128,114)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SandyBrown\" color=\"rgb(244,164,96)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SeaGreen\" color=\"rgb(45,139,87)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"seashell\" color=\"rgb(255,245,238)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"sienna\" color=\"rgb(160,82,45)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"silver\" color=\"rgb(192,192,192)\" compliance=\"SVG\" />"
+    "  <color name=\"SkyBlue\" color=\"rgb(135,206,235)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SlateBlue\" color=\"rgb(106,90,205)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SlateGray\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SlateGrey\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11\" />"
+    "  <color name=\"snow\" color=\"rgb(255,250,250)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SpringGreen\" color=\"rgb(0,255,127)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"SteelBlue\" color=\"rgb(70,130,180)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"tan\" color=\"rgb(210,180,140)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"teal\" color=\"rgb(0,128,128)\" compliance=\"SVG\" />"
+    "  <color name=\"thistle\" color=\"rgb(216,191,216)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"tomato\" color=\"rgb(255,99,71)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"transparent\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
+    "  <color name=\"turquoise\" color=\"rgb(64,224,208)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"violet\" color=\"rgb(238,130,238)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"wheat\" color=\"rgb(245,222,179)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"WhiteSmoke\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11, XPM\" />"
+    "  <color name=\"YellowGreen\" color=\"rgb(154,205,50)\" compliance=\"SVG, X11, XPM\" />"
+    "</colormap>";
+
+/*
+  Typedef declarations.
+*/
+typedef struct _NodeInfo
+{
+  struct _NodeInfo
+    *child[16];
+
+  ColorPacket
+    *list;
+
+  MagickSizeType
+    number_unique;
+
+  unsigned long
+    level;
+} NodeInfo;
+
+typedef struct _Nodes
+{
+  NodeInfo
+    nodes[NodesInAList];
+
+  struct _Nodes
+    *next;
+} Nodes;
+
+typedef struct _CubeInfo
+{
+  NodeInfo
+    *root;
+
+  long
+    x,
+    progress;
+
+  unsigned long
+    colors,
+    free_nodes;
+
+  NodeInfo
+    *node_info;
+
+  Nodes
+    *node_queue;
+} CubeInfo;
+
+/*
+  Static declarations.
+*/
+static LinkedListInfo
+  *color_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *color_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_color = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static CubeInfo
+  *GetCubeInfo(void);
+
+static NodeInfo
+  *GetNodeInfo(CubeInfo *,const unsigned long);
+
+static MagickBooleanType
+  InitializeColorList(ExceptionInfo *),
+  LoadColorLists(const char *,ExceptionInfo *);
+
+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 unsigned long ColorToNodeId(const Image *image,
+  const MagickPixelPacket *pixel,unsigned long index)
+{
+  unsigned long
+    id;
+
+  id=(unsigned long) (
+    ((ScaleQuantumToChar(RoundToQuantum(pixel->red)) >> index) & 0x01) |
+    ((ScaleQuantumToChar(RoundToQuantum(pixel->green)) >> index) & 0x01) << 1 |
+    ((ScaleQuantumToChar(RoundToQuantum(pixel->blue)) >> index) & 0x01) << 2);
+  if (image->matte != MagickFalse)
+    id|=((ScaleQuantumToChar(RoundToQuantum(pixel->opacity)) >> index) &
+      0x01) << 3;
+  return(id);
+}
+
+static CubeInfo *ClassifyImageColors(const Image *image,
+  ExceptionInfo *exception)
+{
+#define EvaluateImageTag  "  Compute image colors...  "
+
+  CubeInfo
+    *cube_info;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  MagickPixelPacket
+    pixel,
+    target;
+
+  NodeInfo
+    *node_info;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i,
+    x;
+
+  register unsigned long
+    id,
+    index,
+    level;
+
+  CacheView
+    *image_view;
+
+  /*
+    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);
+    }
+  GetMagickPixelPacket(image,&pixel);
+  GetMagickPixelPacket(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0; x < (long) 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++)
+      {
+        SetMagickPixelPacket(image,p,indexes+x,&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 < (long) node_info->number_unique; i++)
+      {
+        SetMagickPixelPacket(image,&node_info->list[i].pixel,
+          &node_info->list[i].index,&target);
+        if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (long) node_info->number_unique)
+        node_info->list[i].count++;
+      else
+        {
+          if (node_info->number_unique == 0)
+            node_info->list=(ColorPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (ColorPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              return(0);
+            }
+          node_info->list[i].pixel=(*p);
+          if ((image->colorspace == CMYKColorspace) ||
+              (image->storage_class == PseudoClass))
+            node_info->list[i].index=indexes[x];
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+        }
+      p++;
+    }
+    proceed=SetImageProgress(image,EvaluateImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(cube_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 MagickPixelPacket *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 MagickPixelPacket *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=QuantumRange-pixel->opacity;
+      break;
+    }
+    case IndexChannel:
+    {
+      color=pixel->index;
+      break;
+    }
+    default:
+      break;
+  }
+  if (compliance != SVGCompliance)
+    {
+      if (pixel->depth > 16)
+        {
+          (void) FormatMagickString(component,MaxTextExtent,"%10lu",
+            (unsigned long) ScaleQuantumToLong(RoundToQuantum(color)));
+          (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+          return;
+        }
+      if (pixel->depth > 8)
+        {
+          (void) FormatMagickString(component,MaxTextExtent,"%5d",
+            ScaleQuantumToShort(RoundToQuantum(color)));
+          (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+          return;
+        }
+      (void) FormatMagickString(component,MaxTextExtent,"%3d",
+        ScaleQuantumToChar(RoundToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (channel == OpacityChannel)
+    {
+      (void) FormatMagickString(component,MaxTextExtent,"%g",
+        (double) (QuantumScale*color));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 8)
+    {
+      (void) FormatMagickString(component,MaxTextExtent,"%g%%",
+        (double) (100.0*QuantumScale*color));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  (void) FormatMagickString(component,MaxTextExtent,"%d",
+    ScaleQuantumToChar(RoundToQuantum(color)));
+  (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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,
+%        ColorPacket **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,
+  ColorPacket **histogram)
+{
+  register long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      DefineImageHistogram(image,node_info->child[i],histogram);
+  if (node_info->level == (MaxTreeDepth-1))
+    {
+      register ColorPacket
+        *p;
+
+      p=node_info->list;
+      for (i=0; i < (long) node_info->number_unique; i++)
+      {
+        (*histogram)->pixel=p->pixel;
+        (*histogram)->index=p->index;
+        (*histogram)->count=p->count;
+        (*histogram)++;
+        p++;
+      }
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C o l o r L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyColorList() deallocates memory associated with the color list.
+%
+%  The format of the DestroyColorList method is:
+%
+%      DestroyColorList(void)
+%
+*/
+
+static void *DestroyColorElement(void *color_info)
+{
+  register ColorInfo
+    *p;
+
+  p=(ColorInfo *) color_info;
+  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 DestroyColorList(void)
+{
+  AcquireSemaphoreInfo(&color_semaphore);
+  if (color_list != (LinkedListInfo *) NULL)
+    color_list=DestroyLinkedList(color_list,DestroyColorElement);
+  instantiate_color=MagickFalse;
+  RelinquishSemaphoreInfo(color_semaphore);
+  DestroySemaphoreInfo(&color_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      DestroyColorCube(image,node_info->child[i]);
+  if (node_info->list != (ColorPacket *) NULL)
+    node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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)
+{
+  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.
+  */
+  AcquireSemaphoreInfo(&color_semaphore);
+  ResetLinkedListIterator(color_list);
+  p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  while (p != (const ColorInfo *) NULL)
+  {
+    if (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));
+  RelinquishSemaphoreInfo(color_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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,
+%        unsigned long *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,
+  unsigned long *number_colors,ExceptionInfo *exception)
+{
+  const ColorInfo
+    **colors;
+
+  register const ColorInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate color list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_colors != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(color_semaphore);
+  qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
+  colors[i]=(ColorInfo *) NULL;
+  *number_colors=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_colors,ExceptionInfo *exception)
+{
+  char
+    **colors;
+
+  register const ColorInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate color list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_colors != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(color_semaphore);
+  qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
+  colors[i]=(char *) NULL;
+  *number_colors=(unsigned long) 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 MagickPixelPacket *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 MagickPixelPacket *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 OpacityChannel:
+    {
+      color=(MagickRealType) QuantumRange-pixel->opacity;
+      break;
+    }
+    case IndexChannel:
+    {
+      color=pixel->index;
+      break;
+    }
+    default:
+      break;
+  }
+  if (pixel->depth > 32)
+    {
+      (void) FormatMagickString(component,MaxTextExtent,"%08lX",
+        ScaleQuantumToLong(RoundToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 16)
+    {
+      (void) FormatMagickString(component,MaxTextExtent,"%08X",
+        (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 8)
+    {
+      (void) FormatMagickString(component,MaxTextExtent,"%04X",
+        ScaleQuantumToShort(RoundToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  (void) FormatMagickString(component,MaxTextExtent,"%02X",
+    ScaleQuantumToChar(RoundToQuantum(color)));
+  (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+  return;
+}
+
+MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
+  const MagickBooleanType hex,char *tuple)
+{
+  MagickPixelPacket
+    color;
+
+  assert(pixel != (const MagickPixelPacket *) 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,IndexChannel,tuple);
+      if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
+        ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
+      return;
+    }
+  /*
+    Convert pixel to rgb() or cmyk() color.
+  */
+  color=(*pixel);
+  if (color.depth > 8)
+    {
+#define SVGCompliant(component) ((MagickRealType) \
+   ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(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.index == SVGCompliant(color.index);
+      if (color.matte != MagickFalse)
+        status&=color.opacity == SVGCompliant(color.opacity);
+      if (status != MagickFalse)
+        color.depth=8;
+    }
+  (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
+    MagickColorspaceOptions,(long) 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,IndexChannel,SVGCompliance,tuple);
+    }
+  if (color.matte != MagickFalse)
+    {
+      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+      ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
+    }
+  (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
+  LocaleLower(tuple);
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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:
+%
+%      unsigned long GetImageHistogram(const Image *image,
+%        unsigned long *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 ColorPacket *GetImageHistogram(const Image *image,
+  unsigned long *number_colors,ExceptionInfo *exception)
+{
+  ColorPacket
+    *histogram;
+
+  CubeInfo
+    *cube_info;
+
+  *number_colors=0;
+  histogram=(ColorPacket *) NULL;
+  cube_info=ClassifyImageColors(image,exception);
+  if (cube_info != (CubeInfo *) NULL)
+    {
+      histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
+        sizeof(*histogram));
+      if (histogram == (ColorPacket *) NULL)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      else
+        {
+          ColorPacket
+            *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 unsigned long 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 unsigned long 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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:
+%
+%      unsigned long 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 ColorPacket
+    *color_1,
+    *color_2;
+
+  color_1=(const ColorPacket *) x;
+  color_2=(const ColorPacket *) y;
+  if (color_2->pixel.red != color_1->pixel.red)
+    return((int) color_1->pixel.red-(int) color_2->pixel.red);
+  if (color_2->pixel.green != color_1->pixel.green)
+    return((int) color_1->pixel.green-(int) color_2->pixel.green);
+  if (color_2->pixel.blue != color_1->pixel.blue)
+    return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
+  return((int) color_2->count-(int) color_1->count);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport unsigned long GetNumberColors(const Image *image,FILE *file,
+  ExceptionInfo *exception)
+{
+#define HistogramImageTag  "Histogram/Image"
+
+  char
+    color[MaxTextExtent],
+    hex[MaxTextExtent],
+    tuple[MaxTextExtent];
+
+  ColorPacket
+    *histogram;
+
+  MagickPixelPacket
+    pixel;
+
+  register ColorPacket
+    *p;
+
+  register long
+    i;
+
+  unsigned long
+    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 == (ColorPacket *) NULL)
+    return(number_colors);
+  qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
+    HistogramCompare);
+  GetMagickPixelPacket(image,&pixel);
+  p=histogram;
+  for (i=0; i < (long) number_colors; i++)
+  {
+    SetMagickPixelPacket(image,&p->pixel,&p->index,&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,IndexChannel,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) fprintf(file,MagickSizeFormat,p->count);
+    (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
+    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
+        (QuantumTick(i,number_colors) != MagickFalse))
+      (void) image->progress_monitor(HistogramImageTag,i,number_colors,
+        image->client_data);
+    p++;
+  }
+  (void) fflush(file);
+  histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
+  return(number_colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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))
+    {
+      AcquireSemaphoreInfo(&color_semaphore);
+      if ((color_list == (LinkedListInfo *) NULL) &&
+          (instantiate_color == MagickFalse))
+        {
+          (void) LoadColorLists(ColorFilename,exception);
+          instantiate_color=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(color_semaphore);
+    }
+  return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s C o l o r S i m i l a r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsColorSimilar() returns MagickTrue if the distance between two colors is
+%  less than the specified distance in a linear three dimensional color space.
+%  This method is used by ColorFloodFill() and other algorithms which
+%  compare two colors.
+%
+%  The format of the IsColorSimilar method is:
+%
+%      void IsColorSimilar(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 IsColorSimilar(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    alpha,
+    beta,
+    distance;
+
+  if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
+    return(IsColorEqual(p,q));
+  fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
+    MagickSQ1_2);
+  alpha=1.0;
+  beta=1.0;
+  if (image->matte != MagickFalse)
+    {
+      alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+      beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
+    }
+  pixel=alpha*p->red-beta*q->red;
+  distance=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=alpha*p->green-beta*q->green;
+  distance+=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=alpha*p->blue-beta*q->blue;
+  distance+=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s G r a y I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsGrayImage() returns MagickTrue if all the pixels in the image have the
+%  same red, green, and blue intensities.
+%
+%  The format of the IsGrayImage method is:
+%
+%      MagickBooleanType IsGrayImage(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 IsGrayImage(const Image *image,
+  ExceptionInfo *exception)
+{
+  ImageType
+    type;
+
+  register const PixelPacket
+    *p;
+
+  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;
+  switch (image->storage_class)
+  {
+    case DirectClass:
+    case UndefinedClass:
+    {
+      long
+        y;
+
+      register long
+        x;
+
+      CacheView
+        *image_view;
+
+      image_view=AcquireCacheView(image);
+      for (y=0; y < (long) image->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          if (IsGrayPixel(p) == MagickFalse)
+            {
+              type=UndefinedType;
+              break;
+            }
+          if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
+            type=GrayscaleType;
+          p++;
+        }
+        if (type == UndefinedType)
+          break;
+      }
+      image_view=DestroyCacheView(image_view);
+      break;
+    }
+    case PseudoClass:
+    {
+      register long
+        i;
+
+      p=image->colormap;
+      for (i=0; i < (long) image->colors; i++)
+      {
+        if (IsGrayPixel(p) == MagickFalse)
+          {
+            type=UndefinedType;
+            break;
+          }
+        if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
+          type=GrayscaleType;
+        p++;
+      }
+      break;
+    }
+  }
+  if (type == UndefinedType)
+    return(MagickFalse);
+  ((Image *) image)->type=type;
+  if ((type == GrayscaleType) && (image->matte != MagickFalse))
+    ((Image *) image)->type=GrayscaleMatteType;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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
+
+  CubeInfo
+    *cube_info;
+
+  long
+    y;
+
+  MagickPixelPacket
+    pixel,
+    target;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    x;
+
+  register NodeInfo
+    *node_info;
+
+  register long
+    i;
+
+  unsigned long
+    id,
+    index,
+    level;
+
+  CacheView
+    *image_view;
+
+  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);
+    }
+  GetMagickPixelPacket(image,&pixel);
+  GetMagickPixelPacket(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0; x < (long) 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++)
+      {
+        SetMagickPixelPacket(image,p,indexes+x,&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 < (long) node_info->number_unique; i++)
+      {
+        SetMagickPixelPacket(image,&node_info->list[i].pixel,
+          &node_info->list[i].index,&target);
+        if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (long) 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=(ColorPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (ColorPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              break;
+            }
+          node_info->list[i].pixel=(*p);
+          if ((image->colorspace == CMYKColorspace) ||
+              (image->storage_class == PseudoClass))
+            node_info->list[i].index=indexes[x];
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+          if (cube_info->colors > MaximumUniqueColors)
+            break;
+        }
+      p++;
+    }
+    if (x < (long) image->columns)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(y < (long) image->rows ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s I m a g e S i m i l a r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageSimilar() returns true if the target is similar to a region of the
+%  image.
+%
+%  The format of the IsImageSimilar method is:
+%
+%      MagickBooleanType IsImageSimilar(const Image *image,
+%        const Image *target_image,long *x_offset,long *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 IsImageSimilar(const Image *image,
+  const Image *target_image,long *x_offset,long *y_offset,
+  ExceptionInfo *exception)
+{
+#define SearchImageText  "  Searching image...  "
+
+  long
+    j,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    target,
+    pixel;
+
+  register const PixelPacket
+    *p,
+    *q;
+
+  register const IndexPacket
+    *indexes,
+    *target_indexes;
+
+  register long
+    i,
+    x;
+
+  CacheView
+    *image_view,
+    *target_view;
+
+  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 != (long *) NULL);
+  assert(y_offset != (long *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  x=0;
+  GetMagickPixelPacket(image,&pixel);
+  GetMagickPixelPacket(image,&target);
+  image_view=AcquireCacheView(image);
+  target_view=AcquireCacheView(target_image);
+  for (y=(*y_offset); y < (long) image->rows; y++)
+  {
+    for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
+    {
+      for (j=0; j < (long) target_image->rows; j++)
+      {
+        for (i=0; i < (long) target_image->columns; i++)
+        {
+          p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
+          indexes=GetCacheViewVirtualIndexQueue(image_view);
+          SetMagickPixelPacket(image,p,indexes,&pixel);
+          q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
+          target_indexes=GetCacheViewVirtualIndexQueue(target_view);
+          SetMagickPixelPacket(image,q,target_indexes,&target);
+          if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
+            break;
+        }
+        if (i < (long) target_image->columns)
+          break;
+      }
+      if (j == (long) target_image->rows)
+        break;
+    }
+    if (x < (long) image->columns)
+      break;
+    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
+        (QuantumTick(y,image->rows) != MagickFalse))
+      {
+        status=image->progress_monitor(SearchImageText,y,image->rows,
+          image->client_data);
+        if (status == MagickFalse)
+          break;
+      }
+  }
+  target_view=DestroyCacheView(target_view);
+  image_view=DestroyCacheView(image_view);
+  *x_offset=x;
+  *y_offset=y;
+  return(y < (long) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s M a g i c k C o l o r S i m i l a r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickColorSimilar() returns true if the distance between two colors is
+%  less than the specified distance in a linear three dimensional color space.
+%  This method is used by ColorFloodFill() and other algorithms which
+%  compare two colors.
+%
+%  The format of the IsMagickColorSimilar method is:
+%
+%      MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
+%        const MagickPixelPacket *q)
+%
+%  A description of each parameter follows:
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+*/
+MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
+  const MagickPixelPacket *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    alpha,
+    beta,
+    distance;
+
+  if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
+    return(IsMagickColorEqual(p,q));
+  if (p->fuzz == 0.0)
+    fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
+  else
+    if (q->fuzz == 0.0)
+      fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
+    else
+      fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
+  alpha=1.0;
+  if (p->matte != MagickFalse)
+    alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+  beta=1.0;
+  if (q->matte != MagickFalse)
+    beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
+  if (p->colorspace == CMYKColorspace)
+    {
+      alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
+      beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
+    }
+  pixel=alpha*p->red-beta*q->red;
+  if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
+      (p->colorspace == HWBColorspace))
+    {
+      if (fabs(p->red-q->red) > (QuantumRange/2))
+        {
+          if (p->red > (QuantumRange/2))
+            pixel=alpha*(p->red-QuantumRange)-beta*q->red;
+          else
+            pixel=alpha*p->red-beta*(q->red-QuantumRange);
+        }
+        pixel*=2;
+     }
+  distance=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=alpha*p->green-beta*q->green;
+  distance+=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=alpha*p->blue-beta*q->blue;
+  distance+=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=p->opacity-q->opacity;
+  distance+=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s M o n o c h r o m e I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMonochromeImage() 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 IsMonochromeImage method is:
+%
+%      MagickBooleanType IsMonochromeImage(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 IsMonochromeImage(const Image *image,
+  ExceptionInfo *exception)
+{
+  ImageType
+    type;
+
+  register const PixelPacket
+    *p;
+
+  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;
+  switch (image->storage_class)
+  {
+    case DirectClass:
+    case UndefinedClass:
+    {
+      long
+        y;
+
+      register long
+        x;
+
+      CacheView
+        *image_view;
+
+      image_view=AcquireCacheView(image);
+      for (y=0; y < (long) image->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          if (IsMonochromePixel(p) == MagickFalse)
+            {
+              type=UndefinedType;
+              break;
+            }
+          p++;
+        }
+        if (type == UndefinedType)
+          break;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (y == (long) image->rows)
+        ((Image *) image)->type=BilevelType;
+      break;
+    }
+    case PseudoClass:
+    {
+      register long
+        i;
+
+      p=image->colormap;
+      for (i=0; i < (long) image->colors; i++)
+      {
+        if (IsMonochromePixel(p) == MagickFalse)
+          {
+            type=UndefinedType;
+            break;
+          }
+        p++;
+      }
+      break;
+    }
+  }
+  if (type == UndefinedType)
+    return(MagickFalse);
+  ((Image *) image)->type=type;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s O p a c i t y S i m i l a r                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsOpacitySimilar() returns true if the distance between two opacity
+%  values is less than the specified distance in a linear color space.  This
+%  method is used by MatteFloodFill() and other algorithms which compare
+%  two opacity values.
+%
+%  The format of the IsOpacitySimilar method is:
+%
+%      void IsOpacitySimilar(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 IsOpacitySimilar(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    distance;
+
+  if (image->matte == MagickFalse)
+    return(MagickTrue);
+  if (p->opacity == q->opacity)
+    return(MagickTrue);
+  fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
+  pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
+  distance=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s O p a q u e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
+%  an opacity value other than opaque (0).
+%
+%  The format of the IsOpaqueImage method is:
+%
+%      MagickBooleanType IsOpaqueImage(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 IsOpaqueImage(const Image *image,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    x;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (p->opacity != OpaqueOpacity)
+        break;
+      p++;
+    }
+    if (x < (long) image->columns)
+     break;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(y < (long) 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)
+{
+  CubeInfo
+    *cube_info;
+
+  long
+    y;
+
+  MagickPixelPacket
+    pixel,
+    target;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    x;
+
+  register NodeInfo
+    *node_info;
+
+  register long
+    i;
+
+  unsigned long
+    id,
+    index,
+    level;
+
+  CacheView
+    *image_view;
+
+  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);
+    }
+  GetMagickPixelPacket(image,&pixel);
+  GetMagickPixelPacket(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0; x < (long) 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++)
+      {
+        SetMagickPixelPacket(image,p,indexes+x,&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 < (long) node_info->number_unique; i++)
+      {
+        SetMagickPixelPacket(image,&node_info->list[i].pixel,
+          &node_info->list[i].index,&target);
+        if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (long) 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=(ColorPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (ColorPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              break;
+            }
+          node_info->list[i].pixel=(*p);
+          if ((image->colorspace == CMYKColorspace) ||
+              (image->storage_class == PseudoClass))
+            node_info->list[i].index=indexes[x];
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+          if (cube_info->colors > 256)
+            break;
+        }
+      p++;
+    }
+    if (x < (long) image->columns)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(y < (long) image->rows ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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 long
+    i;
+
+  unsigned long
+    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 < (long) 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) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
+        (void) fprintf(file,"Name                  Color                  "
+          "                       Compliance\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=color_info[i]->path;
+    (void) fprintf(file,"%-21.21s ",color_info[i]->name);
+    GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
+    (void) fprintf(file,"%-45.45s ",tuple);
+    if ((color_info[i]->compliance & SVGCompliance) != 0)
+      (void) fprintf(file,"SVG ");
+    if ((color_info[i]->compliance & X11Compliance) != 0)
+      (void) fprintf(file,"X11 ");
+    if ((color_info[i]->compliance & XPMCompliance) != 0)
+      (void) fprintf(file,"XPM ");
+    (void) fprintf(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 unsigned long 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 unsigned long 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->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)
+          {
+            long
+              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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadColorList(ColorMap,"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|=LoadColorList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((color_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(color_list) != MagickFalse))
+    status|=LoadColorList(ColorMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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.
+%
+*/
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType QueryColorDatabase(const char *name,
+  PixelPacket *color,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    pixel;
+
+  status=QueryMagickColor(name,&pixel,exception);
+  color->opacity=RoundToQuantum(pixel.opacity);
+  if (pixel.colorspace == CMYKColorspace)
+    {
+      color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
+        QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
+        pixel.index)+pixel.index))));
+      color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
+        QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
+        pixel.index)+pixel.index))));
+      color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
+        QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
+        pixel.index)+pixel.index))));
+      return(status);
+    }
+  color->red=RoundToQuantum(pixel.red);
+  color->green=RoundToQuantum(pixel.green);
+  color->blue=RoundToQuantum(pixel.blue);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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)
+{
+  MagickPixelPacket
+    pixel;
+
+  GetMagickPixelPacket(image,&pixel);
+  SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
+  return(QueryMagickColorname(image,&pixel,compliance,name,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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,
+%        MagickPixelPacket *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,
+  MagickPixelPacket *color,ExceptionInfo *exception)
+{
+  GeometryInfo
+    geometry_info;
+
+  long
+    type;
+
+  MagickRealType
+    scale;
+
+  MagickStatusType
+    flags;
+
+  register const ColorInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Initialize color return value.
+  */
+  assert(name != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  assert(color != (MagickPixelPacket *) NULL);
+  GetMagickPixelPacket((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;
+
+      unsigned long
+        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=(long) (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.opacity;
+            pixel.opacity=0;
+            for (i=(long) (n/4-1); i >= 0; i--)
+            {
+              c=(*name++);
+              pixel.opacity<<=4;
+              if ((c >= '0') && (c <= '9'))
+                pixel.opacity|=(int) (c-'0');
+              else
+                if ((c >= 'A') && (c <= 'F'))
+                  pixel.opacity|=(int) c-((int) 'A'-10);
+                else
+                  if ((c >= 'a') && (c <= 'f'))
+                    pixel.opacity|=(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->opacity=(MagickRealType) OpaqueOpacity;
+      if ((n % 3) != 0)
+        {
+          color->matte=MagickTrue;
+          color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
+            pixel.opacity,range));
+        }
+      color->index=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=ParseMagickOption(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) RoundToQuantum(scale*geometry_info.rho);
+      if ((flags & SigmaValue) != 0)
+        color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
+      if ((flags & XiValue) != 0)
+        color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
+      color->opacity=(MagickRealType) OpaqueOpacity;
+      if ((flags & PsiValue) != 0)
+        {
+          if (color->colorspace == CMYKColorspace)
+            color->index=(MagickRealType) RoundToQuantum(scale*
+              geometry_info.psi);
+          else
+            if (color->matte != MagickFalse)
+              color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
+                (QuantumRange-QuantumRange*geometry_info.psi));
+        }
+      if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
+        color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
+          (QuantumRange-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->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
+              (QuantumRange-QuantumRange*geometry_info.sigma));
+        }
+      if (LocaleCompare(colorspace,"HSL") == 0)
+        {
+          PixelPacket
+            pixel;
+
+          geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
+            360.0;
+          geometry_info.sigma/=100.0;
+          geometry_info.xi/=100.0;
+          ConvertHSLToRGB(geometry_info.rho,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=GetColorInfo(name,exception);
+  if (p == (const ColorInfo *) NULL)
+    return(MagickFalse);
+  color->colorspace=RGBColorspace;
+  color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
+  color->red=(MagickRealType) p->color.red;
+  color->green=(MagickRealType) p->color.green;
+  color->blue=(MagickRealType) p->color.blue;
+  color->opacity=(MagickRealType) p->color.opacity;
+  color->index=0.0;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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 MagickPixelPacket *color,const ComplianceType compliance,
+  char *name,ExceptionInfo *exception)
+{
+  MagickPixelPacket
+    pixel;
+
+  MagickRealType
+    opacity;
+
+  register const ColorInfo
+    *p;
+
+  *name='\0';
+  pixel=(*color);
+  if (compliance == XPMCompliance)
+    {
+      pixel.matte=MagickFalse;
+      pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
+      GetColorTuple(&pixel,MagickTrue,name);
+      return(MagickTrue);
+    }
+  GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
+    name);
+  (void) GetColorInfo("*",exception);
+  ResetLinkedListIterator(color_list);
+  opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
+  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.opacity == opacity))
+      {
+        (void) CopyMagickString(name,p->name,MaxTextExtent);
+        break;
+      }
+    p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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 *image,CubeInfo *cube_info,
+  const NodeInfo *node_info,ExceptionInfo *exception)
+{
+#define UniqueColorsImageTag  "UniqueColors/Image"
+
+  register long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      UniqueColorsToImage(image,cube_info,node_info->child[i],exception);
+  if (node_info->level == (MaxTreeDepth-1))
+    {
+      register ColorPacket
+        *p;
+
+      register IndexPacket
+        *__restrict indexes;
+
+      register PixelPacket
+        *__restrict q;
+
+      p=node_info->list;
+      for (i=0; i < (long) node_info->number_unique; i++)
+      {
+        q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception);
+        if (q == (PixelPacket *) NULL)
+          continue;
+        indexes=GetAuthenticIndexQueue(image);
+        *q=p->pixel;
+        if (image->colorspace == CMYKColorspace)
+          *indexes=p->index;
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+        cube_info->x++;
+        p++;
+      }
+      if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
+          (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse))
+        (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress,
+          cube_info->colors,image->client_data);
+      cube_info->progress++;
+    }
+}
+
+MagickExport Image *UniqueImageColors(const Image *image,
+  ExceptionInfo *exception)
+{
+  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);
+    }
+  UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception);
+  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/magick/color.h b/magick/color.h
new file mode 100644
index 0000000..eaed174
--- /dev/null
+++ b/magick/color.h
@@ -0,0 +1,125 @@
+/*
+  Copyright 1999-2009 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 <magick/pixel.h>
+#include <magick/exception.h>
+
+typedef enum
+{
+  UndefinedCompliance,
+  NoCompliance = 0x0000,
+  SVGCompliance = 0x0001,
+  X11Compliance = 0x0002,
+  XPMCompliance = 0x0004,
+  AllCompliance = 0x7fffffff
+} ComplianceType;
+
+typedef struct _ColorInfo
+{
+  char
+    *path,
+    *name;
+
+  ComplianceType
+    compliance;
+
+  MagickPixelPacket
+    color;
+
+  MagickBooleanType
+    stealth;
+
+  struct _ColorInfo
+    *previous,
+    *next;  /* deprecated, use GetColorInfoList() */
+
+  unsigned long
+    signature;
+} ColorInfo;
+
+typedef struct _ColorPacket
+{
+  PixelPacket
+    pixel;
+
+  IndexPacket
+    index;
+
+  MagickSizeType
+    count;
+} ColorPacket;
+
+typedef struct _ErrorInfo
+{
+  double
+    mean_error_per_pixel,
+    normalized_mean_error,
+    normalized_maximum_error;
+} ErrorInfo;
+
+extern MagickExport char
+  **GetColorList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const ColorInfo
+  *GetColorInfo(const char *,ExceptionInfo *),
+  **GetColorInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport ColorPacket
+  *GetImageHistogram(const Image *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport Image
+  *UniqueImageColors(const Image *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  IsColorSimilar(const Image *,const PixelPacket *,const PixelPacket *),
+  IsGrayImage(const Image *,ExceptionInfo *),
+  IsHistogramImage(const Image *,ExceptionInfo *),
+  IsImageSimilar(const Image *,const Image *,long *x,long *y,ExceptionInfo *),
+  IsMagickColorSimilar(const MagickPixelPacket *,const MagickPixelPacket *),
+  IsMonochromeImage(const Image *,ExceptionInfo *),
+  IsOpacitySimilar(const Image *,const PixelPacket *,const PixelPacket *),
+  IsOpaqueImage(const Image *,ExceptionInfo *),
+  IsPaletteImage(const Image *,ExceptionInfo *),
+  ListColorInfo(FILE *,ExceptionInfo *),
+  QueryColorDatabase(const char *,PixelPacket *,ExceptionInfo *),
+  QueryColorname(const Image *,const PixelPacket *,const ComplianceType,char *,
+    ExceptionInfo *),
+  QueryMagickColor(const char *,MagickPixelPacket *,ExceptionInfo *),
+  QueryMagickColorname(const Image *,const MagickPixelPacket *,
+    const ComplianceType,char *,ExceptionInfo *);
+
+extern MagickExport unsigned long
+  GetNumberColors(const Image *,FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  ConcatenateColorComponent(const MagickPixelPacket *,const ChannelType,
+    const ComplianceType,char *),
+  DestroyColorList(void),
+  GetColorTuple(const MagickPixelPacket *,const MagickBooleanType,char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/colorspace-private.h b/magick/colorspace-private.h
new file mode 100644
index 0000000..a8a15e9
--- /dev/null
+++ b/magick/colorspace-private.h
@@ -0,0 +1,71 @@
+/*
+  Copyright 1999-2009 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 <magick/pixel.h>
+
+static inline void ConvertRGBToCMYK(MagickPixelPacket *pixel)
+{
+  MagickRealType
+    black,
+    cyan,
+    magenta,
+    yellow;
+                                                                                
+  cyan=(MagickRealType) (QuantumRange-pixel->red);
+  magenta=(MagickRealType) (QuantumRange-pixel->green);
+  yellow=(MagickRealType) (QuantumRange-pixel->blue);
+  black=(MagickRealType) QuantumRange;
+  if (cyan < black)
+    black=cyan;
+  if (magenta < black)
+    black=magenta;
+  if (yellow < black)
+    black=yellow;
+  if (black == QuantumRange)
+    {
+      cyan=0.0;
+      magenta=0.0;
+      yellow=0.0;
+    }
+  else
+    {
+      cyan=(MagickRealType) (QuantumRange*(cyan-black)/
+        (QuantumRange-black));
+      magenta=(MagickRealType) (QuantumRange*(magenta-black)/
+        (QuantumRange-black));
+      yellow=(MagickRealType) (QuantumRange*(yellow-black)/
+        (QuantumRange-black));
+    }
+  pixel->colorspace=CMYKColorspace;
+  pixel->red=cyan;
+  pixel->green=magenta;
+  pixel->blue=yellow;
+  pixel->index=black;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/colorspace.c b/magick/colorspace.c
new file mode 100644
index 0000000..2611ed2
--- /dev/null
+++ b/magick/colorspace.c
@@ -0,0 +1,2366 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/colorspace-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/gem.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel-private.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/string_.h"
+#include "magick/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;
+  g=QuantumScale*green;
+  b=QuantumScale*blue;
+  *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 inline void ConvertXYZToLab(const double X,const double Y,const double Z,
+  double *L,double *a,double *b)
+{
+  double
+    x,
+    y,
+    z;
+
+  assert(L != (double *) NULL);
+  assert(a != (double *) NULL);
+  assert(b != (double *) NULL);
+  x=X/0.9504559271;
+  if (x > (216/24389.0))
+    x=pow(x,1.0/3.0);
+  else 
+    x=(7.787*x)+(16.0/116.0);
+  y=Y/1.00000;
+  if (y > (216/24389.0))
+    y=pow(y,1.0/3.0);
+  else
+    y=(7.787*y)+(16.0/116.0);
+  z=Z/1.0890577508;
+  if (z > (216/24389.0))
+    z=pow(z,1.0/3.0);
+  else
+    z=(7.787*z)+(16.0/116.0);
+  *L=0.5*((1.160*y)-0.160+1.0);
+  *a=0.5*(5.000*(x-y)+1.0);
+  *b=0.5*(2.000*(y-z)+1.0);
+}
+
+MagickExport MagickBooleanType RGBTransformImage(Image *image,
+  const ColorspaceType colorspace)
+{
+#define RGBTransformImageTag  "RGBTransform/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status,
+    sync;
+
+  PrimaryInfo
+    primary_info;
+
+  register long
+    i;
+
+  TransformPacket
+    *x_map,
+    *y_map,
+    *z_map;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+      {
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=RoundToQuantum((MagickRealType) (QuantumRange-q->red));
+          q->green=RoundToQuantum((MagickRealType) (QuantumRange-q->green));
+          q->blue=RoundToQuantum((MagickRealType) (QuantumRange-q->blue));
+          q++;
+        }
+        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:
+    {
+      MagickPixelPacket
+        zero;
+
+      /*
+        Convert RGB to CMYK colorspace.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      GetMagickPixelPacket(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 < (long) image->rows; y++)
+      {
+        MagickPixelPacket
+          pixel;
+
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        pixel=zero;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          SetMagickPixelPacket(image,q,indexes+x,&pixel);
+          ConvertRGBToCMYK(&pixel);
+          SetPixelPacket(image,&pixel,q,indexes+x);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          brightness,
+          hue,
+          saturation;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        saturation=0.0;
+        brightness=0.0;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          ConvertRGBToHSB(q->red,q->green,q->blue,&hue,&saturation,&brightness);
+          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
+          q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
+          q->blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          hue,
+          lightness,
+          saturation;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        saturation=0.0;
+        lightness=0.0;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          ConvertRGBToHSL(q->red,q->green,q->blue,&hue,&saturation,&lightness);
+          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
+          q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
+          q->blue=RoundToQuantum((MagickRealType) QuantumRange*lightness);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          blackness,
+          hue,
+          whiteness;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        whiteness=0.0;
+        blackness=0.0;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          ConvertRGBToHWB(q->red,q->green,q->blue,&hue,&whiteness,&blackness);
+          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
+          q->green=RoundToQuantum((MagickRealType) QuantumRange*whiteness);
+          q->blue=RoundToQuantum((MagickRealType) QuantumRange*blackness);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          a,
+          b,
+          L,
+          X,
+          Y,
+          Z;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) 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 < (long) image->columns; x++)
+        {
+          ConvertRGBToXYZ(q->red,q->green,q->blue,&X,&Y,&Z);
+          ConvertXYZToLab(X,Y,Z,&L,&a,&b);
+          q->red=RoundToQuantum((MagickRealType) QuantumRange*L);
+          q->green=RoundToQuantum((MagickRealType) QuantumRange*a);
+          q->blue=RoundToQuantum((MagickRealType) QuantumRange*b);
+          q++;
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case LogColorspace:
+    {
+#define ReferenceBlack  95.0
+#define ReferenceWhite  685.0
+#define DisplayGamma  (1.0/1.7)
+
+      const char
+        *value;
+
+      double
+        black,
+        density,
+        gamma,
+        reference_black,
+        reference_white;
+
+      Quantum
+        *logmap;
+
+      /*
+        Transform RGB to Log colorspace.
+      */
+      density=2.03728;
+      gamma=DisplayGamma;
+      value=GetImageProperty(image,"gamma");
+      if (value != (const char *) NULL)
+        gamma=1.0/atof(value) != 0.0 ? atof(value) : 1.0;
+      reference_black=ReferenceBlack;
+      value=GetImageProperty(image,"reference-black");
+      if (value != (const char *) NULL)
+        reference_black=atof(value);
+      reference_white=ReferenceWhite;
+      value=GetImageProperty(image,"reference-white");
+      if (value != (const char *) NULL)
+        reference_white=atof(value);
+      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/0.6);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (long) MaxMap; i++)
+        logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
+          log10(black+((MagickRealType) i/MaxMap)*(1.0-black))/((gamma/density)*
+          0.002/0.6))/1024.0+0.5));
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (long) image->rows; y++)
+      {
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=(long) image->columns; x != 0; x--)
+        {
+          q->red=logmap[ScaleQuantumToMap(q->red)];
+          q->green=logmap[ScaleQuantumToMap(q->green)];
+          q->blue=logmap[ScaleQuantumToMap(q->blue)];
+          q++;
+        }
+        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 <= (long) 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 <= (long) 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 <= (long) 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 <= (long) 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 <= (long) 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 RGB to nonlinear sRGB (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 <= (long) MaxMap; i++)
+      {
+        MagickRealType
+          v;
+
+        v=(MagickRealType) i/(MagickRealType) MaxMap;
+        if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.03928f)
+          v/=12.92f;
+        else
+          v=(MagickRealType) MaxMap*pow((((double) i/MaxMap)+0.055)/1.055,2.4);
+        x_map[i].x=1.0f*v;
+        y_map[i].x=0.0f*v;
+        z_map[i].x=0.0f*v;
+        x_map[i].y=0.0f*v;
+        y_map[i].y=1.0f*v;
+        z_map[i].y=0.0f*v;
+        x_map[i].z=0.0f*v;
+        y_map[i].z=0.0f*v;
+        z_map[i].z=1.0f*v;
+      }
+      break;
+    }
+    case XYZColorspace:
+    {
+      /*
+        Initialize CIE XYZ tables (ITU-R 709 RGB):
+
+          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
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (long) MaxMap; i++)
+      {
+        x_map[i].x=0.4124240f*(MagickRealType) i;
+        y_map[i].x=0.3575790f*(MagickRealType) i;
+        z_map[i].x=0.1804640f*(MagickRealType) i;
+        x_map[i].y=0.2126560f*(MagickRealType) i;
+        y_map[i].y=0.7151580f*(MagickRealType) i;
+        z_map[i].y=0.0721856f*(MagickRealType) i;
+        x_map[i].z=0.0193324f*(MagickRealType) i;
+        y_map[i].z=0.1191930f*(MagickRealType) i;
+        z_map[i].z=0.9504440f*(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 <= (long) (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 <= (long) 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 <= (long) 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 <= (long) 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 <= (long) 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 < (long) image->rows; y++)
+      {
+        MagickPixelPacket
+          pixel;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        register unsigned long
+          blue,
+          green,
+          red;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          red=ScaleQuantumToMap(q->red);
+          green=ScaleQuantumToMap(q->green);
+          blue=ScaleQuantumToMap(q->blue);
+          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;
+          q->red=ScaleMapToQuantum(pixel.red);
+          q->green=ScaleMapToQuantum(pixel.green);
+          q->blue=ScaleMapToQuantum(pixel.blue);
+          q++;
+        }
+        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 unsigned long
+        blue,
+        green,
+        red;
+
+      /*
+        Convert PseudoClass image.
+      */
+      image_view=AcquireCacheView(image);
+      for (i=0; i < (long) image->colors; i++)
+      {
+        MagickPixelPacket
+          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)
+{
+  Cache
+    cache;
+
+  if (image->colorspace == colorspace)
+    return(MagickTrue);
+  image->colorspace=colorspace;
+  cache=GetImagePixelCache(image,MagickTrue,&image->exception);
+  image->colorspace=colorspace;  /* GRAY colorspace might get reset to RGB */
+  return(cache == (Cache) NULL ? MagickFalse: 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 inline void ConvertLabToXYZ(const double L,const double a,const double b,
+  double *X,double *Y,double *Z)
+{
+  double
+    cube,
+    x,
+    y,
+    z;
+
+  assert(X != (double *) NULL);
+  assert(Y != (double *) NULL);
+  assert(Z != (double *) NULL);
+  y=(100.0*L+16.0)/116.0;
+  x=255.0*(a > 0.5 ? a-1.0 : a)/500.0+y;
+  z=y-255.0*(b > 0.5 ? b-1.0 : b)/200.0;
+  cube=y*y*y;
+  if (cube > 0.008856)
+    y=cube;
+  else
+    y=(y-16.0/116.0)/7.787;
+  cube=x*x*x;
+  if (cube > 0.008856)
+    x=cube;
+  else
+    x=(x-16.0/116.0)/7.787;
+  cube=z*z*z;
+  if (cube > 0.008856)
+    z=cube;
+  else
+    z=(z-16.0/116.0)/7.787;
+  *X=0.9504559271*x;
+  *Y=1.0000000000*y;
+  *Z=1.0890577508*z;
+}
+
+static inline unsigned short RoundToYCC(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return(0UL);
+  if (value >= 350.0)
+    return(350);
+  return((unsigned short) (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(MagickPixelPacket *pixel)
+{
+  pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
+    (QuantumRange-pixel->index)+pixel->index);
+  pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
+    (QuantumRange-pixel->index)+pixel->index);
+  pixel->blue=(MagickRealType) QuantumRange-(QuantumScale*pixel->blue*
+    (QuantumRange-pixel->index)+pixel->index);
+}
+
+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 unsigned char
+    YCCMap[351] =  /* Photo CD information beyond 100% white, Gamma 2.2 */
+    {
+        0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
+       14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
+       28,  29,  30,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
+       43,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  56,  57,  58,
+       59,  60,  61,  62,  63,  64,  66,  67,  68,  69,  70,  71,  72,  73,
+       74,  76,  77,  78,  79,  80,  81,  82,  83,  84,  86,  87,  88,  89,
+       90,  91,  92,  93,  94,  95,  97,  98,  99, 100, 101, 102, 103, 104,
+      105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+      120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
+      135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
+      149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
+      163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
+      176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+      190, 191, 192, 193, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201,
+      202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
+      214, 215, 215, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 224,
+      224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233,
+      234, 234, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241,
+      242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247,
+      248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
+      251, 251, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
+      253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254,
+      254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255,
+      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+      255
+    };
+#endif
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  TransformPacket
+    *y_map,
+    *x_map,
+    *z_map;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=RoundToQuantum((MagickRealType) (QuantumRange-q->red));
+          q->green=RoundToQuantum((MagickRealType) (QuantumRange-q->green));
+          q->blue=RoundToQuantum((MagickRealType) (QuantumRange-q->blue));
+          q++;
+        }
+        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:
+    {
+      MagickPixelPacket
+        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);
+        }
+      GetMagickPixelPacket(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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        MagickPixelPacket
+          pixel;
+
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        pixel=zero;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          SetMagickPixelPacket(image,q,indexes+x,&pixel);
+          ConvertCMYKToRGB(&pixel);
+          SetPixelPacket(image,&pixel,q,indexes+x);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          brightness,
+          hue,
+          saturation;
+
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          hue=(double) (QuantumScale*q->red);
+          saturation=(double) (QuantumScale*q->green);
+          brightness=(double) (QuantumScale*q->blue);
+          ConvertHSBToRGB(hue,saturation,brightness,&q->red,&q->green,&q->blue);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          hue,
+          lightness,
+          saturation;
+
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          hue=(double) (QuantumScale*q->red);
+          saturation=(double) (QuantumScale*q->green);
+          lightness=(double) (QuantumScale*q->blue);
+          ConvertHSLToRGB(hue,saturation,lightness,&q->red,&q->green,&q->blue);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          blackness,
+          hue,
+          whiteness;
+
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          hue=(double) (QuantumScale*q->red);
+          whiteness=(double) (QuantumScale*q->green);
+          blackness=(double) (QuantumScale*q->blue);
+          ConvertHWBToRGB(hue,whiteness,blackness,&q->red,&q->green,&q->blue);
+          q++;
+        }
+        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 < (long) image->rows; y++)
+      {
+        double
+          a,
+          b,
+          L,
+          X,
+          Y,
+          Z;
+
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        X=0.0;
+        Y=0.0;
+        Z=0.0;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          L=QuantumScale*q->red;
+          a=QuantumScale*q->green;
+          b=QuantumScale*q->blue;
+          ConvertLabToXYZ(L,a,b,&X,&Y,&Z);
+          ConvertXYZToRGB(X,Y,Z,&q->red,&q->green,&q->blue);
+          q++;
+        }
+        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,
+        gamma,
+        reference_black,
+        reference_white;
+
+      Quantum
+        *logmap;
+
+      /*
+        Transform Log to RGB colorspace.
+      */
+      density=2.03728;
+      gamma=DisplayGamma;
+      value=GetImageProperty(image,"gamma");
+      if (value != (const char *) NULL)
+        gamma=1.0/atof(value) != 0.0 ? atof(value) : 1.0;
+      reference_black=ReferenceBlack;
+      value=GetImageProperty(image,"reference-black");
+      if (value != (const char *) NULL)
+        reference_black=atof(value);
+      reference_white=ReferenceWhite;
+      value=GetImageProperty(image,"reference-white");
+      if (value != (const char *) NULL)
+        reference_white=atof(value);
+      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/0.6);
+      for (i=0; i <= (long) (reference_black*MaxMap/1024.0); i++)
+        logmap[i]=(Quantum) 0;
+      for ( ; i < (long) (reference_white*MaxMap/1024.0); i++)
+        logmap[i]=RoundToQuantum((MagickRealType) QuantumRange/(1.0-black)*
+          (pow(10.0,(1024.0*i/MaxMap-reference_white)*
+          (gamma/density)*0.002/0.6)-black));
+      for ( ; i <= (long) 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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=(long) image->columns; x != 0; x--)
+        {
+          q->red=logmap[ScaleQuantumToMap(q->red)];
+          q->green=logmap[ScaleQuantumToMap(q->green)];
+          q->blue=logmap[ScaleQuantumToMap(q->blue)];
+          q++;
+        }
+        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 <= (long) 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 <= (long) 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 <= (long) 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 <= (long) 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.2407100*X-1.5372600*Y-0.4985710*Z
+          G = -0.9692580*X+1.8759900*Y+0.0415557*Z
+          B =  0.0556352*X-0.2039960*Y+1.0570700*Z
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (long) MaxMap; i++)
+      {
+        x_map[i].x=3.2407100f*(MagickRealType) i;
+        x_map[i].y=(-0.9692580f)*(MagickRealType) i;
+        x_map[i].z=0.0556352f*(MagickRealType) i;
+        y_map[i].x=(-1.5372600f)*(MagickRealType) i;
+        y_map[i].y=1.8759900f*(MagickRealType) i;
+        y_map[i].z=(-0.2039960f)*(MagickRealType) i;
+        z_map[i].x=(-0.4985710f)*(MagickRealType) i;
+        z_map[i].y=0.0415557f*(MagickRealType) i;
+        z_map[i].z=1.0570700f*(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 <= (long) 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 <= (long) 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 <= (long) 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 <= (long) 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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        MagickPixelPacket
+          pixel;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          register unsigned long
+            blue,
+            green,
+            red;
+
+          red=ScaleQuantumToMap(q->red);
+          green=ScaleQuantumToMap(q->green);
+          blue=ScaleQuantumToMap(q->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)
+              pixel.red=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
+                255.0*QuantumScale*pixel.red)]);
+              pixel.green=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
+                255.0*QuantumScale*pixel.green)]);
+              pixel.blue=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
+                255.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;
+          }
+          q->red=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
+            pixel.red);
+          q->green=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
+            pixel.green);
+          q->blue=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
+            pixel.blue);
+          q++;
+        }
+        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 < (long) image->colors; i++)
+      {
+        MagickPixelPacket
+          pixel;
+
+        register unsigned long
+          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=ScaleCharToQuantum(YCCMap[RoundToYCC(
+              255.0*QuantumScale*pixel.red)]);
+            image->colormap[i].green=ScaleCharToQuantum(YCCMap[RoundToYCC(
+              255.0*QuantumScale*pixel.green)]);
+            image->colormap[i].blue=ScaleCharToQuantum(YCCMap[RoundToYCC(
+              255.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/magick/colorspace.h b/magick/colorspace.h
new file mode 100644
index 0000000..56170ce
--- /dev/null
+++ b/magick/colorspace.h
@@ -0,0 +1,62 @@
+/*
+  Copyright 1999-2009 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/magick/compare.c b/magick/compare.c
new file mode 100644
index 0000000..6e05119
--- /dev/null
+++ b/magick/compare.c
@@ -0,0 +1,1584 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/colorspace-private.h"
+#include "magick/compare.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/resource_.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/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,AllChannels,
+    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)
+{
+  const char
+    *artifact;
+
+  Image
+    *difference_image,
+    *highlight_image;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    highlight,
+    lowlight,
+    zero;
+
+  CacheView
+    *highlight_view,
+    *image_view,
+    *reconstruct_view;
+
+  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;
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    MagickPixelPacket
+      pixel,
+      reconstruct_pixel;
+
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register IndexPacket
+      *__restrict highlight_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 PixelPacket *) NULL) ||
+        (q == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    highlight_indexes=GetCacheViewAuthenticIndexQueue(highlight_view);
+    pixel=zero;
+    reconstruct_pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickStatusType
+        difference;
+
+      SetMagickPixelPacket(image,p,indexes+x,&pixel);
+      SetMagickPixelPacket(reconstruct_image,q,reconstruct_indexes+x,
+        &reconstruct_pixel);
+      difference=MagickFalse;
+      if (channel == AllChannels)
+        {
+          if (IsMagickColorSimilar(&pixel,&reconstruct_pixel) == MagickFalse)
+            difference=MagickTrue;
+        }
+      else
+        {
+          if (((channel & RedChannel) != 0) && (p->red != q->red))
+            difference=MagickTrue;
+          if (((channel & GreenChannel) != 0) && (p->green != q->green))
+            difference=MagickTrue;
+          if (((channel & BlueChannel) != 0) && (p->blue != q->blue))
+            difference=MagickTrue;
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte != MagickFalse) && (p->opacity != q->opacity))
+            difference=MagickTrue;
+          if ((((channel & IndexChannel) != 0) &&
+               (image->colorspace == CMYKColorspace) &&
+               (reconstruct_image->colorspace == CMYKColorspace)) &&
+              (indexes[x] != reconstruct_indexes[x]))
+            difference=MagickTrue;
+        }
+      if (difference != MagickFalse)
+        SetPixelPacket(highlight_image,&highlight,r,highlight_indexes+x);
+      else
+        SetPixelPacket(highlight_image,&lowlight,r,highlight_indexes+x);
+      p++;
+      q++;
+      r++;
+    }
+    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,AllChannels,
+    metric,distortion,exception);
+  return(status);
+}
+
+static MagickBooleanType GetAbsoluteError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,double *distortion,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  /*
+    Compute the absolute difference in pixels between two images.
+  */
+  status=MagickTrue;
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    MagickPixelPacket
+      pixel,
+      reconstruct_pixel;
+
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    pixel=zero;
+    reconstruct_pixel=pixel;
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,p,indexes+x,&pixel);
+      SetMagickPixelPacket(reconstruct_image,q,reconstruct_indexes+x,
+        &reconstruct_pixel);
+      if (IsMagickColorSimilar(&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 & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            channel_distortion[BlackChannel]++;
+          channel_distortion[AllChannels]++;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetAbsoluteError)
+#endif
+    for (i=0; i <= (long) AllChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+static unsigned long GetNumberChannels(const Image *image,
+  const ChannelType channel)
+{
+  unsigned long
+    channels;
+
+  channels=0;
+  if ((channel & RedChannel) != 0)
+    channels++;
+  if ((channel & GreenChannel) != 0)
+    channels++;
+  if ((channel & BlueChannel) != 0)
+    channels++;
+  if (((channel & OpacityChannel) != 0) &&
+       (image->matte != MagickFalse))
+    channels++;
+  if (((channel & IndexChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    channels++;
+  return(channels);
+}
+
+static MagickBooleanType GetMeanAbsoluteError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  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 < (long) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->red-(double) q->red);
+          channel_distortion[RedChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->green-(double) q->green);
+          channel_distortion[GreenChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->blue-(double) q->blue);
+          channel_distortion[BlueChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*fabs(p->opacity-(double) q->opacity);
+          channel_distortion[OpacityChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*fabs(indexes[x]-(double)
+            reconstruct_indexes[x]);
+          channel_distortion[BlackChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanAbsoluteError)
+#endif
+    for (i=0; i <= (long) AllChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (long) AllChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[AllChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
+static MagickBooleanType GetMeanErrorPerPixel(Image *image,
+  const Image *reconstruct_image,const ChannelType channel,double *distortion,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    alpha,
+    area,
+    beta,
+    maximum_error,
+    mean_error;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        break;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte != MagickFalse)
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+          if (reconstruct_image->matte != MagickFalse)
+            beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
+        }
+      if ((channel & RedChannel) != 0)
+        {
+          distance=fabs(alpha*p->red-beta*q->red);
+          distortion[RedChannel]+=distance;
+          distortion[AllChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=fabs(alpha*p->green-beta*q->green);
+          distortion[GreenChannel]+=distance;
+          distortion[AllChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=fabs(alpha*p->blue-beta*q->blue);
+          distortion[BlueChannel]+=distance;
+          distortion[AllChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=fabs((double) p->opacity-q->opacity);
+          distortion[OpacityChannel]+=distance;
+          distortion[AllChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=fabs(alpha*indexes[x]-beta*reconstruct_indexes[x]);
+          distortion[BlackChannel]+=distance;
+          distortion[AllChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      p++;
+      q++;
+    }
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  image->error.mean_error_per_pixel=distortion[AllChannels]/area;
+  image->error.normalized_mean_error=QuantumScale*QuantumScale*mean_error/area;
+  image->error.normalized_maximum_error=QuantumScale*maximum_error;
+  return(status);
+}
+
+static MagickBooleanType GetMeanSquaredError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  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 < (long) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*(p->red-(MagickRealType) q->red);
+          channel_distortion[RedChannel]+=distance*distance;
+          channel_distortion[AllChannels]+=distance*distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*(p->green-(MagickRealType) q->green);
+          channel_distortion[GreenChannel]+=distance*distance;
+          channel_distortion[AllChannels]+=distance*distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*(p->blue-(MagickRealType) q->blue);
+          channel_distortion[BlueChannel]+=distance*distance;
+          channel_distortion[AllChannels]+=distance*distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*(p->opacity-(MagickRealType) q->opacity);
+          channel_distortion[OpacityChannel]+=distance*distance;
+          channel_distortion[AllChannels]+=distance*distance;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*(indexes[x]-(MagickRealType)
+            reconstruct_indexes[x]);
+          channel_distortion[BlackChannel]+=distance*distance;
+          channel_distortion[AllChannels]+=distance*distance;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanSquaredError)
+#endif
+    for (i=0; i <= (long) AllChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (long) AllChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[AllChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
+static MagickBooleanType GetPeakAbsoluteError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  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 < (long) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->red-(double) q->red);
+          if (distance > channel_distortion[RedChannel])
+            channel_distortion[RedChannel]=distance;
+          if (distance > channel_distortion[AllChannels])
+            channel_distortion[AllChannels]=distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->green-(double) q->green);
+          if (distance > channel_distortion[GreenChannel])
+            channel_distortion[GreenChannel]=distance;
+          if (distance > channel_distortion[AllChannels])
+            channel_distortion[AllChannels]=distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->blue-(double) q->blue);
+          if (distance > channel_distortion[BlueChannel])
+            channel_distortion[BlueChannel]=distance;
+          if (distance > channel_distortion[AllChannels])
+            channel_distortion[AllChannels]=distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*fabs(p->opacity-(double) q->opacity);
+          if (distance > channel_distortion[OpacityChannel])
+            channel_distortion[OpacityChannel]=distance;
+          if (distance > channel_distortion[AllChannels])
+            channel_distortion[AllChannels]=distance;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*fabs(indexes[x]-(double)
+            reconstruct_indexes[x]);
+          if (distance > channel_distortion[BlackChannel])
+            channel_distortion[BlackChannel]=distance;
+          if (distance > channel_distortion[AllChannels])
+            channel_distortion[AllChannels]=distance;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetPeakAbsoluteError)
+#endif
+    for (i=0; i <= (long) AllChannels; 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=GetMeanSquaredError(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 & IndexChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    distortion[BlackChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[BlackChannel]));
+  distortion[AllChannels]=20.0*log10((double) 1.0/sqrt(
+    distortion[AllChannels]));
+  return(status);
+}
+
+static MagickBooleanType GetRootMeanSquaredError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetMeanSquaredError(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 & OpacityChannel) != 0) &&
+      (image->matte != MagickFalse))
+    distortion[OpacityChannel]=sqrt(distortion[OpacityChannel]);
+  if (((channel & IndexChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    distortion[BlackChannel]=sqrt(distortion[BlackChannel]);
+  distortion[AllChannels]=sqrt(distortion[AllChannels]);
+  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=AllChannels+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=GetAbsoluteError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanAbsoluteErrorMetric:
+    {
+      status=GetMeanAbsoluteError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanErrorPerPixelMetric:
+    {
+      status=GetMeanErrorPerPixel(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanSquaredErrorMetric:
+    {
+      status=GetMeanSquaredError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakAbsoluteErrorMetric:
+    default:
+    {
+      status=GetPeakAbsoluteError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakSignalToNoiseRatioMetric:
+    {
+      status=GetPeakSignalToNoiseRatio(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case RootMeanSquaredErrorMetric:
+    {
+      status=GetRootMeanSquaredError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+  }
+  *distortion=channel_distortion[AllChannels];
+  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=AllChannels+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=GetAbsoluteError(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanAbsoluteErrorMetric:
+    {
+      status=GetMeanAbsoluteError(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanErrorPerPixelMetric:
+    {
+      status=GetMeanErrorPerPixel(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanSquaredErrorMetric:
+    {
+      status=GetMeanSquaredError(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakAbsoluteErrorMetric:
+    default:
+    {
+      status=GetPeakAbsoluteError(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakSignalToNoiseRatioMetric:
+    {
+      status=GetPeakSignalToNoiseRatio(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case RootMeanSquaredErrorMetric:
+    {
+      status=GetRootMeanSquaredError(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
+  }
+  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)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    area,
+    maximum_error,
+    mean_error,
+    mean_error_per_pixel;
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      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 PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      break;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      distance=fabs(p->red-(double) q->red);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      distance=fabs(p->green-(double) q->green);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      distance=fabs(p->blue-(double) q->blue);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      if (image->matte != MagickFalse)
+        {
+          distance=fabs(p->opacity-(double) q->opacity);
+          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(indexes[x]-(double) reconstruct_indexes[x]);
+          mean_error_per_pixel+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      p++;
+      q++;
+    }
+  }
+  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 GetSimilarityMetric(const Image *image,const Image *reference,
+  const long x_offset,const long y_offset,ExceptionInfo *exception)
+{
+  double
+    similarity;
+
+  long
+    y;
+
+  CacheView
+    *image_view,
+    *reference_view;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Compute the similarity in pixels between two images.
+  */
+  status=MagickTrue;
+  similarity=0.0;
+  image_view=AcquireCacheView(image);
+  reference_view=AcquireCacheView(reference);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (long) reference->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes,
+      *__restrict reference_indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset+y,
+      reference->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reference_view,0,y,reference->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reference_indexes=GetCacheViewVirtualIndexQueue(reference_view);
+    for (x=0; x < (long) reference->columns; x++)
+    {
+      double
+        thread_similarity;
+
+      MagickRealType
+        distance;
+
+      thread_similarity=0.0;
+      distance=QuantumScale*(p->red-(MagickRealType) q->red);
+      thread_similarity+=distance*distance;
+      distance=QuantumScale*(p->green-(MagickRealType) q->green);
+      thread_similarity+=distance*distance;
+      distance=QuantumScale*(p->blue-(MagickRealType) q->blue);
+      thread_similarity+=distance*distance;
+      if ((image->matte != MagickFalse) && (reference->matte != MagickFalse))
+        {
+          distance=QuantumScale*(p->opacity-(MagickRealType) q->opacity);
+          thread_similarity+=distance*distance;
+        }
+      if ((image->colorspace == CMYKColorspace) &&
+          (reference->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*(indexes[x]-(MagickRealType)
+            reference_indexes[x]);
+          thread_similarity+=distance*distance;
+        }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetSimilarityMetric)
+#endif
+      similarity+=thread_similarity;
+      p++;
+      q++;
+    }
+  }
+  reference_view=DestroyCacheView(reference_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    return(0.0);
+  similarity/=((double) reference->columns*reference->rows);
+  similarity/=(double) GetNumberChannels(reference,AllChannels);
+  return(sqrt(similarity));
+}
+
+MagickExport Image *SimilarityImage(Image *image,const Image *reference,
+  RectangleInfo *offset,double *similarity_metric,ExceptionInfo *exception)
+{
+#define SimilarityImageTag  "Similarity/Image"
+
+  long
+    progress,
+    y;
+
+  Image
+    *similarity_image;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *similarity_view;
+
+  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;
+  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 < (long) (image->rows-reference->rows+1); y++)
+  {
+    double
+      similarity;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(similarity_view,0,y,
+      similarity_image->columns,1,exception);
+    if (q == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) (image->columns-reference->columns+1); x++)
+    {
+      similarity=GetSimilarityMetric(image,reference,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;
+        }
+      q->red=RoundToQuantum(QuantumRange-QuantumRange*similarity);
+      q->green=q->red;
+      q->blue=q->red;
+      q++;
+    }
+    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);
+  return(similarity_image);
+}
diff --git a/magick/compare.h b/magick/compare.h
new file mode 100644
index 0000000..c530018
--- /dev/null
+++ b/magick/compare.h
@@ -0,0 +1,62 @@
+/*
+  Copyright 1999-2009 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 "magick/image.h"
+
+typedef enum
+{
+  UndefinedMetric,
+  AbsoluteErrorMetric,
+  MeanAbsoluteErrorMetric,
+  MeanErrorPerPixelMetric,
+  MeanSquaredErrorMetric,
+  PeakAbsoluteErrorMetric,
+  PeakSignalToNoiseRatioMetric,
+  RootMeanSquaredErrorMetric
+} 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/magick/composite-private.h b/magick/composite-private.h
new file mode 100644
index 0000000..04d957b
--- /dev/null
+++ b/magick/composite-private.h
@@ -0,0 +1,161 @@
+/*
+  Copyright 1999-2009 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 "magick/color.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+
+static inline MagickRealType RoundToUnity(const MagickRealType value)
+{
+  return(value < 0.0 ? 0.0 : (value > 1.0) ? 1.0 : value);
+}
+
+static inline MagickRealType MagickOver_(const MagickRealType p,
+  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
+{
+  return((1.0-QuantumScale*alpha)*p+
+         (1.0-QuantumScale*beta)*q*QuantumScale*alpha);
+}
+
+static inline void MagickCompositeOver(const PixelPacket *p,
+  const MagickRealType alpha,const PixelPacket *q,const MagickRealType beta,
+  PixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  /*
+    Compose pixel p over pixel q with the given opacities.
+  */
+  if (alpha == TransparentOpacity)
+    {
+      if (composite != q)
+        *composite=(*q);
+      return;
+    }
+  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  composite->opacity=(Quantum) (QuantumRange*(1.0-gamma)+0.5);
+  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=(Quantum) (gamma*MagickOver_((MagickRealType) p->red,alpha,
+    (MagickRealType) q->red,beta)+0.5);
+  composite->green=(Quantum) (gamma*MagickOver_((MagickRealType) p->green,alpha,
+    (MagickRealType) q->green,beta)+0.5);
+  composite->blue=(Quantum) (gamma*MagickOver_((MagickRealType) p->blue,alpha,
+    (MagickRealType) q->blue,beta)+0.5);
+#else
+  composite->opacity=(Quantum) (QuantumRange*(1.0-gamma));
+  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=(Quantum) (gamma*MagickOver_((MagickRealType) p->red,alpha,
+    (MagickRealType) q->red,beta));
+  composite->green=(Quantum) (gamma*MagickOver_((MagickRealType) p->green,alpha,
+    (MagickRealType) q->green,beta));
+  composite->blue=(Quantum) (gamma*MagickOver_((MagickRealType) p->blue,alpha,
+    (MagickRealType) q->blue,beta));
+#endif
+}
+
+static inline void MagickPixelCompositeOver(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  /*
+    Compose pixel p over pixel q with the given opacities.
+  */
+  if (alpha == OpaqueOpacity)
+    {
+      *composite=(*p);
+      return;
+    }
+  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
+}
+
+static inline void MagickPixelCompositePlus(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  /*
+    Add two pixels with the given opacities.
+  */
+  Sa=1.0-QuantumScale*alpha;
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da);  /* 'Plus' blending -- not 'Over' blending */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*(Sa*p->index+Da*q->index);
+}
+
+/*
+  Blend pixel colors p and q by the amount given.
+*/
+static inline void MagickPixelCompositeBlend(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickPixelCompositePlus(p,(MagickRealType) (QuantumRange-alpha*
+    (QuantumRange-p->opacity)),q,(MagickRealType) (QuantumRange-beta*
+    (QuantumRange-q->opacity)),composite);
+}
+
+/*
+  Blend pixel colors p and q by the amount given and area.
+*/
+static inline void MagickPixelCompositeAreaBlend(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,const MagickRealType area,
+  MagickPixelPacket *composite)
+{
+  MagickPixelCompositePlus(p,(MagickRealType) QuantumRange-(1.0-area)*
+    (QuantumRange-alpha),q,(MagickRealType) (QuantumRange-area*(QuantumRange-
+    beta)),composite);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/composite.c b/magick/composite.c
new file mode 100644
index 0000000..ff3e831
--- /dev/null
+++ b/magick/composite.c
@@ -0,0 +1,2371 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/resample.h"
+#include "magick/resource_.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/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 long x_offset,const long y_offset)
+%      MagickBooleanType CompositeImageChannel(Image *image,
+%        const ChannelType channel,const CompositeOperator compose,
+%        Image *composite_image,const long x_offset,const long 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
+*/
+
+static inline MagickRealType Add(const MagickRealType p,const MagickRealType q)
+{
+  MagickRealType
+    pixel;
+
+  pixel=p+q;
+  if (pixel > QuantumRange)
+    pixel-=(QuantumRange+1.0);
+  return(pixel);
+}
+
+static inline void CompositeAdd(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  composite->red=Add(p->red,q->red);
+  composite->green=Add(p->green,q->green);
+  composite->blue=Add(p->blue,q->blue);
+  composite->opacity=Add(alpha,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=Add(p->index,q->index);
+}
+
+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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  composite->opacity=beta;    /* optimized  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->index=Atop(p->index,Sa,q->index,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 MagickPixelPacket *p,
+  const MagickRealType magick_unused(alpha),const MagickPixelPacket *q,
+  const MagickRealType magick_unused(beta),MagickPixelPacket *composite)
+{
+  MagickRealType
+    intensity;
+
+  intensity=MagickPixelIntensity(p);
+  composite->red=QuantumScale*intensity*q->red;
+  composite->green=QuantumScale*intensity*q->green;
+  composite->blue=QuantumScale*intensity*q->blue;
+  composite->opacity=(MagickRealType) QuantumScale*intensity*p->opacity;
+  if (q->colorspace == CMYKColorspace)
+    composite->index=QuantumScale*intensity*q->index;
+}
+
+static inline void CompositeClear(const MagickPixelPacket *q,
+  MagickPixelPacket *composite)
+{
+  composite->opacity=(MagickRealType) TransparentOpacity;
+  composite->red=0.0;
+  composite->green=0.0;
+  composite->blue=0.0;
+  if (q->colorspace == CMYKColorspace)
+    composite->index=0.0;
+}
+
+static MagickRealType ColorBurn(const MagickRealType Sca,
+  const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
+{
+#if 0
+  /*
+    Oct 2004 SVG specification.
+  */
+  if (Sca*Da + Dca*Sa <= Sa*Da)
+    return(Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Sa*(Sca*Da+Dca*Sa-Sa*Da)/Sca + Sca*(1.0-Da) + Dca*(1.0-Sa));
+#else
+  /*
+    March 2009 SVG specification.
+  */
+  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));
+#endif
+}
+
+static inline void CompositeColorBurn(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*ColorBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+
+static MagickRealType ColorDodge(const MagickRealType Sca,
+  const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
+{
+#if 0
+  /*
+    Oct 2004 SVG specification.
+  */
+  if ((Sca*Da+Dca*Sa) >= Sa*Da)
+    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) );
+#endif
+#if 0
+  /*
+    New specification, March 2009 SVG specification.  This specification was
+    also wrong of non-overlap cases.
+  */
+  if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+    return(Sca*(1.0-Da));
+  if (fabs(Sca-Sa) < MagickEpsilon)
+    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Sa*MagickMin(Da,Dca*Sa/(Sa-Sca)));
+#endif
+  /*
+    Working from first principles using the original formula:
+
+       f(Sc,Dc) = Dc/(1-Sc)
+
+    This works correctly! Looks like the 2004 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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*ColorDodge(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Darken(p->red,alpha,q->red,beta);
+  composite->green=gamma*Darken(p->green,alpha,q->green,beta);
+  composite->blue=gamma*Darken(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*Darken(p->index,alpha,q->index,beta);
+}
+
+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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  /*
+    Values not normalized as an optimization.
+  */
+  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->index=gamma*Difference(p->index,Sa,q->index,Da);
+}
+
+static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
+  const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    Divide:
+
+      f(Sc,Dc) = Sc/Dc
+
+    But with appropriate handling for special case of Dc == 0 specifically
+    f(Black,Black)  = Black and f(non-Black,Black) = White.  It is however
+    also important to correctly do 'over' alpha blending which is why it
+    becomes so complex looking.
+  */
+  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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Divide(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma,
+    Sa,
+    Da;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Exclusion(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*HardLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*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 alpha,const MagickRealType magick_unused(q),
+  const MagickRealType beta)
+{
+  return((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta));
+}
+
+static inline void CompositeIn(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  gamma=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta);
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*In(p->red,alpha,q->red,beta);
+  composite->green=gamma*In(p->green,alpha,q->green,beta);
+  composite->blue=gamma*In(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*In(p->index,alpha,q->index,beta);
+}
+
+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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  composite->opacity=QuantumScale*alpha*beta;    /* optimized 1-gamma */
+  gamma=1.0-QuantumScale*composite->opacity;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Lighten(p->red,alpha,q->red,beta);
+  composite->green=gamma*Lighten(p->green,alpha,q->green,beta);
+  composite->blue=gamma*Lighten(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*Lighten(p->index,alpha,q->index,beta);
+}
+
+static inline void CompositeLinearDodge(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  /*
+    Operation performed directly - not need for sub-routine.
+  */
+  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->index=gamma*(p->index*Sa+q->index*Da);
+}
+
+
+static inline MagickRealType LinearBurn(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 + Sc - 1
+  */
+  return(Sca+Dca-Sa*Da);
+}
+
+static inline void CompositeLinearBurn(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*LinearBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+
+static inline MagickRealType LinearLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+#if 0
+  /*
+    Previous formula, only valid for fully-opaque images.
+  */
+  return(Dca+2*Sca-1.0);
+#else
+  /*
+    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);
+#endif
+}
+
+static inline void CompositeLinearLight(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*LinearLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+static inline MagickRealType Mathematics(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
+  const GeometryInfo *geometry_info)
+{
+  /*
+    '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)
+  */
+  return(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));
+}
+
+static inline void CompositeMathematics(const MagickPixelPacket *p,
+  const MagickPixelPacket *q,const GeometryInfo *args,
+  MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*p->opacity;
+  Da=1.0-QuantumScale*q->opacity;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Mathematics(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da,args);
+}
+
+static inline MagickRealType Minus(const MagickRealType Sca,
+  const MagickRealType Dca)
+{
+  return(Sca-Dca);
+}
+
+static inline void CompositeMinus(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa-Da);  /* is this correct?  - I do not think so! */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Minus(p->red*Sa,q->red*Da);
+  composite->green=gamma*Minus(p->green*Sa,q->green*Da);
+  composite->blue=gamma*Minus(p->blue*Sa,q->blue*Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*Minus(p->index*Sa,q->index*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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Multiply(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+static inline MagickRealType Out(const MagickRealType p,
+  const MagickRealType alpha,const MagickRealType magick_unused(q),
+  const MagickRealType beta)
+{
+  return((1.0-QuantumScale*alpha)*p*QuantumScale*beta);
+}
+
+static inline void CompositeOut(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    gamma;
+
+  gamma=(1.0-QuantumScale*alpha)*QuantumScale*beta;
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Out(p->red,alpha,q->red,beta);
+  composite->green=gamma*Out(p->green,alpha,q->green,beta);
+  composite->blue=gamma*Out(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*Out(p->index,alpha,q->index,beta);
+}
+
+static inline void CompositeOver(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickPixelCompositeOver(p,alpha,q,beta,composite);
+}
+
+static MagickRealType PegtopLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    PegTOP Soft-Light alternative: A continuous version of the Softlight
+    function, producing very similar results however it does not take into
+    account alpha channel.
+
+    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*Sca)/Da+Sca*(2*Dca+1-Da)+Dca*(1-Sa));
+}
+
+static inline void CompositePegtopLight(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*PegtopLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*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*Sca-Sa))
+    return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
+  if ((Dca*Sa) > (2*Sca*Da))
+    return(Sca*Da+Sca+Dca*(1.0-Sa));
+  return(Sca*(1.0-Da)+Dca);
+}
+
+static inline void CompositePinLight(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*PinLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+static inline void CompositePlus(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickPixelCompositePlus(p,alpha,q,beta,composite);
+}
+
+static inline MagickRealType Screen(const MagickRealType Sca,
+  const MagickRealType Dca)
+{
+  return(Sca+Dca-Sca*Dca);
+}
+
+static inline void CompositeScreen(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Screen(QuantumScale*p->red*Sa,QuantumScale*
+    q->red*Da);
+  composite->green=gamma*Screen(QuantumScale*p->green*Sa,QuantumScale*
+    q->green*Da);
+  composite->blue=gamma*Screen(QuantumScale*p->blue*Sa,QuantumScale*
+    q->blue*Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=gamma*Screen(QuantumScale*p->index*Sa,QuantumScale*
+      q->index*Da);
+}
+
+static MagickRealType SoftLight(const MagickRealType Sca,
+  const MagickRealType Sa, const MagickRealType Dca, const MagickRealType Da)
+{
+#if 0
+  /*
+    Oct 2004 SVG specification -- spec discovered to be incorrect
+    See  http://lists.w3.org/Archives/Public/www-svg/2009Feb/0014.html.
+  */
+  if (2.0*Sca < Sa)
+    return(Dca*(Sa-(1.0-Dca/Da)*(2.0*Sca-Sa))+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  if (8.0*Dca <= Da)
+    return(Dca*(Sa-(1.0-Dca/Da)*(2.0*Sca-Sa)*(3.0-8.0*Dca/Da))+
+      Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return((Dca*Sa+(pow(Dca/Da,0.5)*Da-Dca)*(2.0*Sca-Sa))+Sca*(1.0-Da)+
+    Dca*(1.0-Sa));
+#else
+  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);
+#endif
+}
+
+static inline void CompositeSoftLight(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*SoftLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+static inline MagickRealType Subtract(const MagickRealType p,
+  const MagickRealType magick_unused(alpha),const MagickRealType q,
+  const MagickRealType magick_unused(beta))
+{
+  MagickRealType
+    pixel;
+
+  pixel=p-q;
+  if (pixel < 0.0)
+    pixel+=(QuantumRange+1.0);
+  return(pixel);
+}
+
+static inline void CompositeSubtract(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  composite->red=Subtract(p->red,alpha,q->red,beta);
+  composite->green=Subtract(p->green,alpha,q->green,beta);
+  composite->blue=Subtract(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=Subtract(p->index,alpha,q->index,beta);
+}
+
+static inline MagickRealType Threshold(const MagickRealType p,
+  const MagickRealType magick_unused(alpha),const MagickRealType q,
+  const MagickRealType magick_unused(beta),const MagickRealType threshold,
+  const MagickRealType amount)
+{
+  MagickRealType
+    delta;
+
+  delta=p-q;
+  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+    return(q);
+  return(q+delta*amount);
+}
+
+static inline void CompositeThreshold(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,const MagickRealType threshold,
+  const MagickRealType amount,MagickPixelPacket *composite)
+{
+  composite->red=Threshold(p->red,alpha,q->red,beta,threshold,amount);
+  composite->green=Threshold(p->green,alpha,q->green,beta,threshold,amount);
+  composite->blue=Threshold(p->blue,alpha,q->blue,beta,threshold,amount);
+  composite->opacity=(MagickRealType) QuantumRange-
+    Threshold(p->opacity,alpha,q->opacity,beta,threshold,amount);
+  if (q->colorspace == CMYKColorspace)
+    composite->index=Threshold(p->index,alpha,q->index,beta,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*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 MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*VividLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
+      q->index*Da,Da);
+}
+
+static MagickRealType Xor(const MagickRealType Sca,const MagickRealType Sa,
+  const MagickRealType Dca,const MagickRealType Da)
+{
+  return(Sca*(1-Da)+Dca*(1-Sa));
+}
+
+static inline void CompositeXor(const MagickPixelPacket *p,
+  const MagickRealType alpha,const MagickPixelPacket *q,
+  const MagickRealType beta,MagickPixelPacket *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
+  Da=1.0-QuantumScale*beta;
+  gamma=Sa+Da-2*Sa*Da;        /* Xor blend mode X=0,Y=1,Z=1 */
+  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+  /*
+    Optimized by multipling QuantumRange taken from 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->index=gamma*Xor(p->index*Sa,Sa,q->index*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 long x_offset,const long y_offset)
+{
+  MagickBooleanType
+    status;
+
+  status=CompositeImageChannel(image,DefaultChannels,compose,composite_image,
+    x_offset,y_offset);
+  return(status);
+}
+
+MagickExport MagickBooleanType CompositeImageChannel(Image *image,
+  const ChannelType magick_unused(channel),const CompositeOperator compose,
+  const Image *composite_image,const long x_offset,const long y_offset)
+{
+#define CompositeImageTag  "Composite/Image"
+
+  CacheView
+    *composite_view,
+    *image_view;
+
+  const char
+    *value;
+
+  double
+    sans;
+
+  ExceptionInfo
+    *exception;
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *destination_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    modify_outside_overlay,
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    amount,
+    destination_dissolve,
+    midpoint,
+    percent_brightness,
+    percent_saturation,
+    source_dissolve,
+    threshold;
+
+  MagickStatusType
+    flags;
+
+  /*
+    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);
+  GetMagickPixelPacket(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 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:
+    {
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        blur_xu,
+        blur_xv,
+        blur_yu,
+        blur_yv;
+
+      ResampleFilter
+        *resample_filter;
+
+      CacheView
+        *composite_view,
+        *dest_view;
+
+      /*
+        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);
+        }
+      blur_xu=geometry_info.rho;
+      blur_yv=geometry_info.sigma;
+      blur_xv=blur_yu = 0.0;
+      if ((flags & HeightValue) == 0)
+        blur_yv=blur_xu;
+      if ((flags & XValue) != 0)
+        {
+          MagickRealType
+            angle,
+            x,
+            y;
+
+          x=blur_xu;
+          y=blur_yv;
+          angle=DegreesToRadians(geometry_info.xi);
+          blur_xu=x*cos(angle);
+          blur_xv=x*sin(angle);
+          blur_yu=(-y*sin(angle));
+          blur_yu=y*cos(angle);
+        }
+      /*
+        Blur Image by resampling;
+      */
+      pixel=zero;
+      exception=(&image->exception);
+      resample_filter=AcquireResampleFilter(image,&image->exception);
+      SetResampleFilter(resample_filter,GaussianFilter,1.0);
+      dest_view=AcquireCacheView(destination_image);
+      composite_view=AcquireCacheView(composite_image);
+      for (y=0; y < (long) composite_image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const PixelPacket
+          *__restrict p;
+
+        register PixelPacket
+          *__restrict r;
+
+        register IndexPacket
+          *__restrict destination_indexes;
+
+        register long
+          x;
+
+        if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
+          continue;
+        p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
+          1,exception);
+        r=QueueCacheViewAuthenticPixels(dest_view,0,y,
+          destination_image->columns,1,&image->exception);
+        if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
+          break;
+        destination_indexes=GetCacheViewAuthenticIndexQueue(dest_view);
+        for (x=0; x < (long) composite_image->columns; x++)
+        {
+          if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
+            {
+              p++;
+              continue;
+            }
+          ScaleResampleFilter(resample_filter,blur_xu*QuantumScale*p->red,
+            blur_yu*QuantumScale*p->green,blur_xv*QuantumScale*p->red,
+            blur_yv*QuantumScale*p->green);
+          (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
+            (double) y_offset+y,&pixel);
+          SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
+          p++;
+          r++;
+        }
+        sync=SyncCacheViewAuthenticPixels(dest_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      resample_filter=DestroyResampleFilter(resample_filter);
+      composite_view=DestroyCacheView(composite_view);
+      dest_view=DestroyCacheView(dest_view);
+      composite_image=destination_image;
+      break;
+    }
+    case DisplaceCompositeOp:
+    case DistortCompositeOp:
+    {
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        horizontal_scale,
+        vertical_scale,
+        x_center,
+        y_center,
+        x_lookup,
+        y_lookup;
+
+      register IndexPacket
+        *__restrict destination_indexes;
+
+      register PixelPacket
+        *__restrict r;
+
+      ResampleFilter
+        *resample_filter;
+
+      CacheView
+        *composite_view,
+        *dest_view;
+
+      /*
+        Displace/Distort based on overlay gradient map:
+          X = red_channel;  Y = green_channel;
+          compose:args = x_scale[,y_scale[,x_center,y_center]]
+      */
+      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 lookup relative to a fixed absolute point
+           Select that point according to +X+Y user inputs.
+           default = center of overlay image
+           flag '!' = locations/percentage relative to background image
+      */
+      x_center=(MagickRealType) x_offset;
+      y_center=(MagickRealType) y_offset;
+      if (compose == DistortCompositeOp)
+        {
+          if ((flags & XValue) == 0)
+            if ((flags & AspectValue) == 0)
+              x_center=(MagickRealType) x_offset+ (composite_image->columns-1)/
+                2.0;
+            else
+              x_center=((MagickRealType) image->columns-1)/2.0;
+          else
+            if ((flags & AspectValue) == 0)
+              x_center=(MagickRealType) x_offset+geometry_info.xi;
+            else
+              x_center=geometry_info.xi;
+          if ((flags & YValue) == 0)
+            if ((flags & AspectValue) == 0)
+              y_center=(MagickRealType) y_offset+
+                (composite_image->rows-1)/2.0;
+            else
+              y_center=((MagickRealType) image->rows-1)/2.0;
+          else
+            if ((flags & AspectValue) == 0)
+              y_center=(MagickRealType) y_offset+geometry_info.psi;
+            else
+              y_center=geometry_info.psi;
+        }
+      /*
+        Shift the pixel lookup point as defined by the provided,
+        displacement/distortion map.  -- Like a lens...
+      */
+      pixel=zero;
+      exception=(&image->exception);
+      resample_filter=AcquireResampleFilter(image,&image->exception);
+      dest_view=AcquireCacheView(destination_image);
+      composite_view=AcquireCacheView(composite_image);
+      for (y=0; y < (long) composite_image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const PixelPacket
+          *__restrict p;
+
+        register long
+          x;
+
+        if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
+          continue;
+        p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
+          1,exception);
+        r=QueueCacheViewAuthenticPixels(dest_view,0,y,
+          destination_image->columns,1,&image->exception);
+        if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
+          break;
+        destination_indexes=GetCacheViewAuthenticIndexQueue(dest_view);
+        for (x=0; x < (long) composite_image->columns; x++)
+        {
+          if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
+            {
+              p++;
+              continue;
+            }
+          /*
+            Displace the lookup.
+          */
+          x_lookup=(horizontal_scale*(p->red-(((MagickRealType) QuantumRange+
+            1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
+            x_center+((compose == DisplaceCompositeOp) ? x : 0);
+          y_lookup=(vertical_scale*(p->green-(((MagickRealType) QuantumRange+
+            1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
+            y_center+((compose == DisplaceCompositeOp) ? y : 0);
+          (void) ResamplePixelColor(resample_filter,(double) x_lookup,
+            (double) y_lookup,&pixel);
+          /*
+            Mask with 'invalid pixel mask' in alpha channel.
+          */
+          pixel.opacity = (MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
+            pixel.opacity)*(1.0-QuantumScale*p->opacity));
+          SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
+          p++;
+          r++;
+        }
+        sync=SyncCacheViewAuthenticPixels(dest_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      resample_filter=DestroyResampleFilter(resample_filter);
+      composite_view=DestroyCacheView(composite_view);
+      dest_view=DestroyCacheView(dest_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;
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    const PixelPacket
+      *pixels;
+
+    double
+      brightness,
+      hue,
+      saturation;
+
+    MagickPixelPacket
+      composite,
+      destination,
+      source;
+
+    register const IndexPacket
+      *__restrict composite_indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    if (modify_outside_overlay == MagickFalse)
+      {
+        if (y < y_offset)
+          continue;
+        if ((y-y_offset) >= (long) composite_image->rows)
+          continue;
+      }
+    /*
+      If pixels is NULL, y is outside overlay region.
+    */
+    pixels=(PixelPacket *) NULL;
+    p=(PixelPacket *) NULL;
+    if ((y >= y_offset) && ((y-y_offset) < (long) composite_image->rows))
+      {
+        p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
+          composite_image->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixels=p;
+        if (x_offset < 0)
+          p-=x_offset;
+      }
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    composite_indexes=GetCacheViewVirtualIndexQueue(composite_view);
+    source=zero;
+    destination=zero;
+    hue=0.0;
+    saturation=0.0;
+    brightness=0.0;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (modify_outside_overlay == MagickFalse)
+        {
+          if (x < x_offset)
+            {
+              q++;
+              continue;
+            }
+          if ((x-x_offset) >= (long) composite_image->columns)
+            break;
+        }
+      destination.red=(MagickRealType) q->red;
+      destination.green=(MagickRealType) q->green;
+      destination.blue=(MagickRealType) q->blue;
+      if (image->matte != MagickFalse)
+        destination.opacity=(MagickRealType) q->opacity;
+      if (image->colorspace == CMYKColorspace)
+        {
+          destination.red=(MagickRealType) QuantumRange-destination.red;
+          destination.green=(MagickRealType) QuantumRange-destination.green;
+          destination.blue=(MagickRealType) QuantumRange-destination.blue;
+          destination.index=(MagickRealType) (QuantumRange-indexes[x]);
+        }
+      /*
+        Handle destination modifications outside overlaid region.
+      */
+      composite=destination;
+      if ((pixels == (PixelPacket *) NULL) || (x < x_offset) ||
+          ((x-x_offset) >= (long) composite_image->columns))
+        {
+          switch (compose)
+          {
+            case DissolveCompositeOp:
+            case BlendCompositeOp:
+            {
+              composite.opacity=(MagickRealType) (QuantumRange-
+                destination_dissolve*(QuantumRange-composite.opacity));
+              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.opacity=(MagickRealType) TransparentOpacity;
+              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.index=(MagickRealType) QuantumRange-composite.index;
+            }
+          q->red=RoundToQuantum(composite.red);
+          q->green=RoundToQuantum(composite.green);
+          q->blue=RoundToQuantum(composite.blue);
+          if (image->matte != MagickFalse)
+            q->opacity=RoundToQuantum(composite.opacity);
+          if (image->colorspace == CMYKColorspace)
+            indexes[x]=RoundToQuantum(composite.index);
+          q++;
+          continue;
+        }
+      /*
+        Handle normal overlay of source onto destination.
+      */
+      source.red=(MagickRealType) p->red;
+      source.green=(MagickRealType) p->green;
+      source.blue=(MagickRealType) p->blue;
+      if (composite_image->matte != MagickFalse)
+        source.opacity=(MagickRealType) p->opacity;
+      if (composite_image->colorspace == CMYKColorspace)
+        {
+          source.red=(MagickRealType) QuantumRange-source.red;
+          source.green=(MagickRealType) QuantumRange-source.green;
+          source.blue=(MagickRealType) QuantumRange-source.blue;
+          source.index=(MagickRealType) QuantumRange-(MagickRealType)
+            composite_indexes[x-x_offset];
+        }
+      switch (compose)
+      {
+        case AddCompositeOp:
+        {
+          CompositeAdd(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case ClearCompositeOp:
+        {
+          CompositeClear(&destination,&composite);
+          break;
+        }
+        case SrcCompositeOp:
+        case CopyCompositeOp:
+        case ReplaceCompositeOp:
+        {
+          composite=source;
+          break;
+        }
+        case ChangeMaskCompositeOp:
+        {
+          if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
+              (IsMagickColorSimilar(&source,&destination) != MagickFalse))
+            composite.opacity=(MagickRealType) TransparentOpacity;
+          else
+            composite.opacity=(MagickRealType) OpaqueOpacity;
+          break;
+        }
+        case DivideCompositeOp:
+        {
+          CompositeDivide(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case DstCompositeOp:
+          break;
+        case OverCompositeOp:
+        case SrcOverCompositeOp:
+        {
+          CompositeOver(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case DstOverCompositeOp:
+        {
+          CompositeOver(&destination,destination.opacity,&source,source.opacity,
+            &composite);
+          break;
+        }
+        case SrcInCompositeOp:
+        case InCompositeOp:
+        {
+          CompositeIn(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case DstInCompositeOp:
+        {
+          CompositeIn(&destination,destination.opacity,&source,source.opacity,
+            &composite);
+          break;
+        }
+        case OutCompositeOp:
+        case SrcOutCompositeOp:
+        {
+          CompositeOut(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case DstOutCompositeOp:
+        {
+          CompositeOut(&destination,destination.opacity,&source,source.opacity,
+            &composite);
+          break;
+        }
+        case AtopCompositeOp:
+        case SrcAtopCompositeOp:
+        {
+          CompositeAtop(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case DstAtopCompositeOp:
+        {
+          CompositeAtop(&destination,destination.opacity,&source,source.opacity,
+            &composite);
+          break;
+        }
+        case XorCompositeOp:
+        {
+          CompositeXor(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case PlusCompositeOp:
+        {
+          CompositePlus(&source,source.opacity,&destination,destination.opacity,
+            &composite);
+          break;
+        }
+        case MultiplyCompositeOp:
+        {
+          CompositeMultiply(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case ScreenCompositeOp:
+        {
+          CompositeScreen(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case DarkenCompositeOp:
+        {
+          CompositeDarken(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case LightenCompositeOp:
+        {
+          CompositeLighten(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case ColorDodgeCompositeOp:
+        {
+          CompositeColorDodge(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case ColorBurnCompositeOp:
+        {
+          CompositeColorBurn(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case LinearDodgeCompositeOp:
+        {
+          CompositeLinearDodge(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case LinearBurnCompositeOp:
+        {
+          CompositeLinearBurn(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case HardLightCompositeOp:
+        {
+          CompositeHardLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case OverlayCompositeOp:
+        {
+          /*
+            Reversed HardLight.
+          */
+          CompositeHardLight(&destination,destination.opacity,&source,
+            source.opacity,&composite);
+          break;
+        }
+        case SoftLightCompositeOp:
+        {
+          CompositeSoftLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case LinearLightCompositeOp:
+        {
+          CompositeLinearLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case PegtopLightCompositeOp:
+        {
+          CompositePegtopLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case VividLightCompositeOp:
+        {
+          CompositeVividLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case PinLightCompositeOp:
+        {
+          CompositePinLight(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case DifferenceCompositeOp:
+        {
+          CompositeDifference(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case ExclusionCompositeOp:
+        {
+          CompositeExclusion(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case MinusCompositeOp:
+        {
+          CompositeMinus(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case BumpmapCompositeOp:
+        {
+          if (source.opacity == TransparentOpacity)
+            break;
+          CompositeBumpmap(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case DissolveCompositeOp:
+        {
+          CompositeOver(&source,(MagickRealType) (QuantumRange-source_dissolve*
+            (QuantumRange-source.opacity)),&destination,(MagickRealType)
+            (QuantumRange-destination_dissolve*(QuantumRange-
+            destination.opacity)),&composite);
+          break;
+        }
+        case BlendCompositeOp:
+        {
+          MagickPixelCompositeBlend(&source,source_dissolve,&destination,
+            destination_dissolve,&composite);
+          break;
+        }
+        case MathematicsCompositeOp:
+        {
+          CompositeMathematics(&source,&destination,&geometry_info,&composite);
+          break;
+        }
+        case BlurCompositeOp:
+        case DisplaceCompositeOp:
+        case DistortCompositeOp:
+        {
+          composite=source;
+          break;
+        }
+        case ThresholdCompositeOp:
+        {
+          CompositeThreshold(&source,source.opacity,&destination,
+            destination.opacity,threshold,amount,&composite);
+          break;
+        }
+        case ModulateCompositeOp:
+        {
+          long
+            offset;
+
+          if (source.opacity == TransparentOpacity)
+            break;
+          offset=(long) (MagickPixelIntensityToQuantum(&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.opacity == TransparentOpacity)
+            break;
+          if (destination.opacity == TransparentOpacity)
+            {
+              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.opacity < destination.opacity)
+            composite.opacity=source.opacity;
+          break;
+        }
+        case SaturateCompositeOp:
+        {
+          if (source.opacity == TransparentOpacity)
+            break;
+          if (destination.opacity == TransparentOpacity)
+            {
+              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.opacity < destination.opacity)
+            composite.opacity=source.opacity;
+          break;
+        }
+        case SubtractCompositeOp:
+        {
+          CompositeSubtract(&source,source.opacity,&destination,
+            destination.opacity,&composite);
+          break;
+        }
+        case LuminizeCompositeOp:
+        {
+          if (source.opacity == TransparentOpacity)
+            break;
+          if (destination.opacity == TransparentOpacity)
+            {
+              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.opacity < destination.opacity)
+            composite.opacity=source.opacity;
+          break;
+        }
+        case ColorizeCompositeOp:
+        {
+          if (source.opacity == TransparentOpacity)
+            break;
+          if (destination.opacity == TransparentOpacity)
+            {
+              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.opacity < destination.opacity)
+            composite.opacity=source.opacity;
+          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.opacity=(MagickRealType) (QuantumRange-
+                MagickPixelIntensityToQuantum(&source));
+              break;
+            }
+          composite.opacity=source.opacity;
+          break;
+        }
+        case CopyBlackCompositeOp:
+        {
+          if (source.colorspace != CMYKColorspace)
+            ConvertRGBToCMYK(&source);
+          composite.index=source.index;
+          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.index=(MagickRealType) QuantumRange-composite.index;
+        }
+      q->red=RoundToQuantum(composite.red);
+      q->green=RoundToQuantum(composite.green);
+      q->blue=RoundToQuantum(composite.blue);
+      q->opacity=RoundToQuantum(composite.opacity);
+      if (image->colorspace == CMYKColorspace)
+        indexes[x]=RoundToQuantum(composite.index);
+      p++;
+      if (p >= (pixels+composite_image->columns))
+        p=pixels;
+      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_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);
+}
diff --git a/magick/composite.h b/magick/composite.h
new file mode 100644
index 0000000..e58769e
--- /dev/null
+++ b/magick/composite.h
@@ -0,0 +1,103 @@
+/*
+  Copyright 1999-2009 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
+{
+  UndefinedCompositeOp,
+  NoCompositeOp,
+  AddCompositeOp,
+  AtopCompositeOp,
+  BlendCompositeOp,
+  BumpmapCompositeOp,
+  ChangeMaskCompositeOp,
+  ClearCompositeOp,
+  ColorBurnCompositeOp,
+  ColorDodgeCompositeOp,
+  ColorizeCompositeOp,
+  CopyBlackCompositeOp,
+  CopyBlueCompositeOp,
+  CopyCompositeOp,
+  CopyCyanCompositeOp,
+  CopyGreenCompositeOp,
+  CopyMagentaCompositeOp,
+  CopyOpacityCompositeOp,
+  CopyRedCompositeOp,
+  CopyYellowCompositeOp,
+  DarkenCompositeOp,
+  DstAtopCompositeOp,
+  DstCompositeOp,
+  DstInCompositeOp,
+  DstOutCompositeOp,
+  DstOverCompositeOp,
+  DifferenceCompositeOp,
+  DisplaceCompositeOp,
+  DissolveCompositeOp,
+  ExclusionCompositeOp,
+  HardLightCompositeOp,
+  HueCompositeOp,
+  InCompositeOp,
+  LightenCompositeOp,
+  LinearLightCompositeOp,
+  LuminizeCompositeOp,
+  MinusCompositeOp,
+  ModulateCompositeOp,
+  MultiplyCompositeOp,
+  OutCompositeOp,
+  OverCompositeOp,
+  OverlayCompositeOp,
+  PlusCompositeOp,
+  ReplaceCompositeOp,
+  SaturateCompositeOp,
+  ScreenCompositeOp,
+  SoftLightCompositeOp,
+  SrcAtopCompositeOp,
+  SrcCompositeOp,
+  SrcInCompositeOp,
+  SrcOutCompositeOp,
+  SrcOverCompositeOp,
+  SubtractCompositeOp,
+  ThresholdCompositeOp,
+  XorCompositeOp,
+  DivideCompositeOp,
+  DistortCompositeOp,
+  BlurCompositeOp,
+  PegtopLightCompositeOp,
+  VividLightCompositeOp,
+  PinLightCompositeOp,
+  LinearDodgeCompositeOp,
+  LinearBurnCompositeOp,
+  MathematicsCompositeOp
+} CompositeOperator;
+
+extern MagickExport MagickBooleanType
+  CompositeImage(Image *,const CompositeOperator,const Image *,const long,
+    const long),
+  CompositeImageChannel(Image *,const ChannelType,const CompositeOperator,
+    const Image *,const long,const long);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/compress.c b/magick/compress.c
new file mode 100644
index 0000000..e025448
--- /dev/null
+++ b/magick/compress.c
@@ -0,0 +1,1478 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/color-private.h"
+#include "magick/cache.h"
+#include "magick/compress.h"
+#include "magick/constitute.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/resource_.h"
+#include "magick/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
+{
+  long
+    offset,
+    line_break;
+
+  unsigned char
+    buffer[10];
+};
+
+typedef struct HuffmanTable
+{
+  unsigned long
+    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 unsigned long 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 long
+    i,
+    x;
+
+  unsigned long
+    code,
+    quantum;
+
+  code=((((unsigned long) data[0] << 8) | (unsigned long) data[1]) << 16) |
+    ((unsigned long) data[2] << 8) | (unsigned long) 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=(long) (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)
+{
+  long
+    n;
+
+  register char
+    *q;
+
+  register unsigned char
+    *p;
+
+  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=(unsigned long) ((byte & mask) != 0 ? 0x01 : 0x00); \
+  mask>>=1;  \
+  if (bit != 0)  \
+    runlength=0;  \
+}
+
+  const HuffmanTable
+    *entry;
+
+  ExceptionInfo
+    *exception;
+
+  HuffmanTable
+    **mb_hash,
+    **mw_hash;
+
+  IndexPacket
+    index;
+
+  int
+    byte;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  register IndexPacket
+    *indexes;
+
+  register long
+    i;
+
+  register unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    *scanline;
+
+  unsigned int
+    bail,
+    color;
+
+  unsigned long
+    bit,
+    code,
+    mask,
+    length,
+    null_lines,
+    runlength;
+
+  /*
+    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);
+  for (y=0; ((y < (long) image->rows) && (null_lines < 3)); )
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Initialize scanline to white.
+    */
+    p=scanline;
+    for (x=0; x < (long) 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 >= (long) 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)+(unsigned long) 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+=entry->count;
+          if ((x+count) > (long) 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+=entry->count;
+          break;
+        }
+        default:
+          break;
+      }
+      code=0;
+      length=0;
+    }
+    /*
+      Transfer scanline to image pixels.
+    */
+    p=scanline;
+    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetAuthenticIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=(IndexPacket) (*p++);
+      indexes[x]=index;
+      *q++=image->colormap[(long) index];
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,LoadImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+    y++;
+  }
+  image->rows=(unsigned long) 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=1 << (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;
+
+  long
+    n,
+    y;
+
+  Image
+    *huffman_image;
+
+  MagickBooleanType
+    proceed;
+
+  register long
+    i,
+    x;
+
+  register const PixelPacket
+    *p;
+
+  register unsigned char
+    *q;
+
+  unsigned char
+    byte,
+    bit,
+    *scanline;
+
+  unsigned long
+    mask,
+    width;
+
+  /*
+    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);
+  width=inject_image->columns;
+  if (LocaleCompare(image_info->magick,"FAX") == 0)
+    width=(unsigned long) 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 < (long) huffman_image->rows; y++)
+  {
+    p=GetVirtualPixels(huffman_image,0,y,huffman_image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) huffman_image->columns; x++)
+    {
+      *q++=(unsigned char) (PixelIntensity(p) >= ((MagickRealType)
+        QuantumRange/2.0) ? 0 : 1);
+      p++;
+    }
+    /*
+      Huffman encode scanline.
+    */
+    q=scanline;
+    for (n=(long) 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-=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-=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);
+}
+
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H u f f m a n 2 D E n c o d e I m a g e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Huffman2DEncodeImage() compresses an image via two-dimensional
+%  Huffman-coding.
+%
+%  The format of the Huffman2DEncodeImage method is:
+%
+%      MagickBooleanType Huffman2DEncodeImage(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 Huffman2DEncodeImage(const ImageInfo *image_info,
+  Image *image,Image *inject_image)
+{
+  char
+    filename[MaxTextExtent];
+
+  FILE
+    *file;
+
+  Image
+    *huffman_image;
+
+  ImageInfo
+    *write_info;
+
+  int
+    unique_file;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  ssize_t
+    count;
+
+  TIFF
+    *tiff;
+
+  uint16
+    fillorder;
+
+  uint32
+    *byte_count,
+    strip_size;
+
+  unsigned char
+    *buffer;
+
+  /*
+    Write image as CCITTFax4 TIFF image to a temporary file.
+  */
+  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);
+  assert(inject_image != (Image *) NULL);
+  assert(inject_image->signature == MagickSignature);
+  huffman_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
+  if (huffman_image == (Image *) NULL)
+    return(MagickFalse);
+  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,
+        "UnableToCreateTemporaryFile",filename);
+      return(MagickFalse);
+    }
+  (void) FormatMagickString(huffman_image->filename,MaxTextExtent,"tiff:%s",
+    filename);
+  write_info=CloneImageInfo(image_info);
+  SetImageInfoFile(write_info,file);
+  write_info->compression=Group4Compression;
+  (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
+  status=WriteImage(write_info,huffman_image);
+  (void) fflush(file);
+  write_info=DestroyImageInfo(write_info);
+  if (status == MagickFalse)
+    return(MagickFalse);
+  tiff=TIFFOpen(filename,"rb");
+  if (tiff == (TIFF *) NULL)
+    {
+      huffman_image=DestroyImage(huffman_image);
+      (void) fclose(file);
+      (void) RelinquishUniqueFileResource(filename);
+      ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
+        image_info->filename);
+      return(MagickFalse);
+    }
+  /*
+    Allocate raw strip buffer.
+  */
+  byte_count=0;
+  (void) TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count);
+  strip_size=byte_count[0];
+  for (i=1; i < (long) TIFFNumberOfStrips(tiff); i++)
+    if (byte_count[i] > strip_size)
+      strip_size=byte_count[i];
+  buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
+    sizeof(*buffer));
+  if (buffer == (unsigned char *) NULL)
+    {
+      TIFFClose(tiff);
+      huffman_image=DestroyImage(huffman_image);
+      (void) fclose(file);
+      (void) RelinquishUniqueFileResource(filename);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image_info->filename);
+    }
+  /*
+    Compress runlength encoded to 2D Huffman pixels.
+  */
+  fillorder=FILLORDER_LSB2MSB;
+  (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder);
+  for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++)
+  {
+    count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,(long)
+      byte_count[i]);
+    if (fillorder == FILLORDER_LSB2MSB)
+      TIFFReverseBits(buffer,(unsigned long) count);
+    (void) WriteBlob(image,(size_t) count,buffer);
+  }
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  TIFFClose(tiff);
+  huffman_image=DestroyImage(huffman_image);
+  (void) fclose(file);
+  (void) RelinquishUniqueFileResource(filename);
+  return(MagickTrue);
+}
+#else
+MagickExport MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
+  Image *image,Image *inject_image)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  (void) inject_image;
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (TIFF)",
+    image->filename);
+  return(MagickFalse);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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
+  {
+    long
+      prefix,
+      suffix,
+      next;
+  } TableType;
+
+  long
+    index;
+
+  register long
+    i;
+
+  TableType
+    *table;
+
+  unsigned long
+    accumulator,
+    number_bits,
+    code_width,
+    last_code,
+    next_index;
+
+  /*
+    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=(unsigned long) pixels[0];
+  for (i=1; i < (long) length; i++)
+  {
+    /*
+      Find string.
+    */
+    index=(long) last_code;
+    while (index != -1)
+      if ((table[index].prefix != (long) last_code) ||
+          (table[index].suffix != (long) pixels[i]))
+        index=table[index].next;
+      else
+        {
+          last_code=(unsigned long) index;
+          break;
+        }
+    if (last_code != (unsigned long) index)
+      {
+        /*
+          Add string.
+        */
+        OutputCode(last_code);
+        table[next_index].prefix=(long) last_code;
+        table[next_index].suffix=(short) pixels[i];
+        table[next_index].next=table[last_code].next;
+        table[last_code].next=(long) 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=(unsigned long) 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 long
+    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=(long) 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 (((long) 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 (((long) count >= (i-3)) || (count >= 127))
+            break;
+        }
+        i-=count;
+        *packbits=(unsigned char) (count-1);
+        for (j=0; j <= (long) 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 long
+    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 < (long) 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/magick/compress.h b/magick/compress.h
new file mode 100644
index 0000000..786292a
--- /dev/null
+++ b/magick/compress.h
@@ -0,0 +1,68 @@
+/*
+  Copyright 1999-2009 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,
+  NoCompression,
+  BZipCompression,
+  DXT1Compression,
+  DXT3Compression,
+  DXT5Compression,
+  FaxCompression,
+  Group4Compression,
+  JPEGCompression,
+  JPEG2000Compression,
+  LosslessJPEGCompression,
+  LZWCompression,
+  RLECompression,
+  ZipCompression,
+  ZipSCompression,
+  PizCompression,
+  Pxr24Compression,
+  B44Compression,
+  B44ACompression
+} CompressionType;
+
+typedef struct _Ascii85Info
+  Ascii85Info;
+
+extern MagickExport MagickBooleanType
+  HuffmanDecodeImage(Image *),
+  HuffmanEncodeImage(const ImageInfo *,Image *,Image *),
+  Huffman2DEncodeImage(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/magick/config.h_vms b/magick/config.h_vms
new file mode 100644
index 0000000..ebeb2c0
--- /dev/null
+++ b/magick/config.h_vms
@@ -0,0 +1,284 @@
+/* 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
diff --git a/magick/configure.c b/magick/configure.c
new file mode 100644
index 0000000..610c597
--- /dev/null
+++ b/magick/configure.c
@@ -0,0 +1,1194 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%          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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ConfigureFilename  "configure.xml"
+
+/*
+  Static declarations.
+*/
+static const char
+  *ConfigureMap = (char *)
+    "<?xml version=\"1.0\"?>"
+    "<configuremap>"
+    "  <configure stealth=\"True\" />"
+    "</configuremap>";
+
+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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C o n f i g u r e L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyConfigureList() deallocates memory associated with the configure list.
+%
+%  The format of the DestroyConfigureList method is:
+%
+%      DestroyConfigureList(void)
+%
+*/
+
+static void *DestroyConfigureElement(void *configure_info)
+{
+  register ConfigureInfo
+    *p;
+
+  p=(ConfigureInfo *) configure_info;
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  if (p->name != (char *) NULL)
+    p->name=DestroyString(p->name);
+  if (p->value != (char *) NULL)
+    p->value=DestroyString(p->value);
+  p=(ConfigureInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void DestroyConfigureList(void)
+{
+  AcquireSemaphoreInfo(&configure_semaphore);
+  if (configure_list != (LinkedListInfo *) NULL)
+    configure_list=DestroyLinkedList(configure_list,DestroyConfigureElement);
+  configure_list=(LinkedListInfo *) NULL;
+  instantiate_configure=MagickFalse;
+  RelinquishSemaphoreInfo(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.
+  */
+  AcquireSemaphoreInfo(&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));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_options,ExceptionInfo *exception)
+{
+  const ConfigureInfo
+    **options;
+
+  register const ConfigureInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_options != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(configure_semaphore);
+  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureInfoCompare);
+  options[i]=(ConfigureInfo *) NULL;
+  *number_options=(unsigned long) 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,
+%        unsigned long *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,
+  unsigned long *number_options,ExceptionInfo *exception)
+{
+  char
+    **options;
+
+  register const ConfigureInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_options != (unsigned long *) NULL);
+  *number_options=0;
+  p=GetConfigureInfo("*",exception);
+  if (p == (const ConfigureInfo *) NULL)
+    return((char **) NULL);
+  AcquireSemaphoreInfo(&configure_semaphore);
+  RelinquishSemaphoreInfo(configure_semaphore);
+  options=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(configure_list)+1UL,sizeof(*options));
+  if (options == (char **) NULL)
+    return((char **) NULL);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(configure_semaphore);
+  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureCompare);
+  options[i]=(char *) NULL;
+  *number_options=(unsigned long) 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) FormatMagickString(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(__WINDOWS__)
+  {
+    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_CONFIGURE_PATH)
+  (void) AppendValueToLinkedList(paths,ConstantString(
+    MAGICKCORE_SHARE_CONFIGURE_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_SHARE_PATH)
+  (void) AppendValueToLinkedList(paths,ConstantString(MAGICKCORE_SHARE_PATH));
+#endif
+#if defined(__WINDOWS__) && !(defined(MAGICKCORE_CONFIGURE_PATH) || defined(MAGICKCORE_SHARE_CONFIGURE_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) FormatMagickString(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) FormatMagickString(path,MaxTextExtent,"%s%s",home,
+          DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+#else
+        (void) FormatMagickString(path,MaxTextExtent,"%s/lib/%s/",home,
+          MAGICKCORE_CONFIGURE_RELATIVE_PATH);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        (void) FormatMagickString(path,MaxTextExtent,"%s/share/%s/",home,
+          MAGICKCORE_SHARE_CONFIGURE_RELATIVE_PATH);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+#endif
+        home=DestroyString(home);
+      }
+    }
+  if (*GetClientPath() != '\0')
+    {
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+      (void) FormatMagickString(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) FormatMagickString(path,MaxTextExtent,"%s/share/%s/",prefix,
+        MAGICKCORE_SHARE_CONFIGURE_RELATIVE_PATH);
+      (void) AppendValueToLinkedList(paths,ConstantString(path));
+      (void) FormatMagickString(path,MaxTextExtent,"%s/lib/%s/",prefix,
+        MAGICKCORE_CONFIGURE_RELATIVE_PATH);
+      (void) AppendValueToLinkedList(paths,ConstantString(path));
+#endif
+    }
+#endif
+  {
+    char
+      *home;
+
+    home=GetEnvironmentValue("HOME");
+    if (home == (char *) NULL)
+      home=GetEnvironmentValue("USERPROFILE");
+    if (home != (char *) NULL)
+      {
+        /*
+          Search $HOME/.magick.
+        */
+        (void) FormatMagickString(path,MaxTextExtent,"%s%s.magick%s",home,
+          DirectorySeparator,DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        home=DestroyString(home);
+      }
+  }
+#if defined(__WINDOWS__)
+  {
+    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) FormatMagickString(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) FormatMagickString(path,MaxTextExtent,"%s%s",module_path,
+          DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        (void) FormatMagickString(path,MaxTextExtent,"%s%s",module_path,
+          "\\inc\\lib\\auto\\Image\\Magick\\");
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+      }
+  }
+#endif
+  /*
+    Search current directory.
+  */
+  (void) AppendValueToLinkedList(paths,ConstantString(""));
+  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))
+    {
+      AcquireSemaphoreInfo(&configure_semaphore);
+      if ((configure_list == (LinkedListInfo *) NULL) &&
+          (instantiate_configure == MagickFalse))
+        {
+          (void) LoadConfigureLists(ConfigureFilename,exception);
+          instantiate_configure=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_options;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",configure_info[i]->path);
+        (void) fprintf(file,"Name          Value\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=configure_info[i]->path;
+    name="unknown";
+    if (configure_info[i]->name != (char *) NULL)
+      name=configure_info[i]->name;
+    (void) fprintf(file,"%s",name);
+    for (j=(long) strlen(name); j <= 12; j++)
+      (void) fprintf(file," ");
+    (void) fprintf(file," ");
+    value="unknown";
+    if (configure_info[i]->value != (char *) NULL)
+      value=configure_info[i]->value;
+    (void) fprintf(file,"%s",value);
+    (void) fprintf(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 unsigned long 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 unsigned long 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;
+  if (xml == (char *) NULL)
+    token=AcquireString(ConfigureMap);
+  else
+    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->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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadConfigureList(ConfigureMap,"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|=LoadConfigureList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((configure_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(configure_list) != MagickFalse))
+    status|=LoadConfigureList(ConfigureMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
diff --git a/magick/configure.h b/magick/configure.h
new file mode 100644
index 0000000..68e2356
--- /dev/null
+++ b/magick/configure.h
@@ -0,0 +1,71 @@
+/*
+  Copyright 1999-2009 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 "magick/hashmap.h"
+
+typedef struct _ConfigureInfo
+{
+  char
+    *path,
+    *name,
+    *value;
+                                                                                
+  MagickBooleanType
+    stealth;
+                                                                                
+  struct _ConfigureInfo
+    *previous,
+    *next;  /* deprecated, use GetConfigureInfoList() */
+
+  unsigned long
+    signature;
+} ConfigureInfo;
+
+extern MagickExport char
+  **GetConfigureList(const char *,unsigned long *,ExceptionInfo *),
+  *GetConfigureOption(const char *);
+
+extern MagickExport const char
+  *GetConfigureValue(const ConfigureInfo *);
+
+extern MagickExport const ConfigureInfo
+  *GetConfigureInfo(const char *,ExceptionInfo *),
+  **GetConfigureInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport LinkedListInfo
+  *DestroyConfigureOptions(LinkedListInfo *),
+  *GetConfigurePaths(const char *,ExceptionInfo *),
+  *GetConfigureOptions(const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListConfigureInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyConfigureList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/constitute.c b/magick/constitute.c
new file mode 100644
index 0000000..3ddfc51
--- /dev/null
+++ b/magick/constitute.c
@@ -0,0 +1,1250 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/cache.h"
+#include "magick/client.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/geometry.h"
+#include "magick/identify.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/pixel.h"
+#include "magick/policy.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/statistic.h"
+#include "magick/stream.h"
+#include "magick/string_.h"
+#include "magick/timer.h"
+#include "magick/transform.h"
+#include "magick/utility.h"
+
+static SemaphoreInfo
+  *constitute_semaphore = (SemaphoreInfo *) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long columns,
+%        const unsigned long 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 unsigned long columns,
+  const unsigned long 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C o n s t i t u t e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyConstitute() destroys the constitute environment.
+%
+%  The format of the DestroyConstitute method is:
+%
+%      DestroyConstitute(void)
+%
+*/
+MagickExport void DestroyConstitute(void)
+{
+  if (constitute_semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&constitute_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+
+      long
+        extent,
+        scene;
+
+      /*
+        Images of the form image-%d.png[1-5].
+      */
+      read_info=CloneImageInfo(image_info);
+      sans=AcquireExceptionInfo();
+      (void) SetImageInfo(read_info,MagickFalse,sans);
+      sans=DestroyExceptionInfo(sans);
+      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
+      images=NewImageList();
+      extent=(long) (read_info->scene+read_info->number_scenes);
+      for (scene=(long) read_info->scene; scene < (long) 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,MagickFalse,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)
+    {
+      (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))
+          {
+            unsigned long
+              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 ((magick_info != (const MagickInfo *) NULL) &&
+      (GetImageDecoder(magick_info) != (DecodeImageHandler *) NULL))
+    {
+      thread_support=GetMagickThreadSupport(magick_info);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        AcquireSemaphoreInfo(&constitute_semaphore);
+      image=GetImageDecoder(magick_info)(read_info,exception);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        RelinquishSemaphoreInfo(constitute_semaphore);
+    }
+  else
+    {
+      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
+      if (delegate_info == (const DelegateInfo *) NULL)
+        {
+          if (IsPathAccessible(read_info->filename) != MagickFalse)
+            (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)
+        AcquireSemaphoreInfo(&constitute_semaphore);
+      (void) InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
+        exception);
+      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+        RelinquishSemaphoreInfo(constitute_semaphore);
+      image=DestroyImageList(image);
+      read_info->temporary=MagickTrue;
+      (void) SetImageInfo(read_info,MagickFalse,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)
+        AcquireSemaphoreInfo(&constitute_semaphore);
+      image=(Image *) (GetImageDecoder(magick_info))(read_info,exception);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        RelinquishSemaphoreInfo(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
+      timestamp[MaxTextExtent];
+
+    const StringInfo
+      *profile;
+
+    next->taint=MagickFalse;
+    if (next->magick_columns == 0)
+      next->magick_columns=next->columns;
+    if (next->magick_rows == 0)
+      next->magick_rows=next->rows;
+    if ((LocaleCompare(magick,"HTTP") != 0) &&
+        (LocaleCompare(magick,"FTP") != 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);
+    value=GetImageProperty(next,"tiff:Orientation");
+    if (value == (char *) NULL)
+      value=GetImageProperty(next,"exif:Orientation");
+    if (value != (char *) NULL)
+      {
+        next->orientation=(OrientationType) atol(value);
+        (void) DeleteImageProperty(next,"tiff:Orientation");
+        (void) DeleteImageProperty(next,"exif:Orientation");
+      }
+    value=GetImageProperty(next,"tiff:XResolution");
+    if (value == (char *) NULL)
+      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");
+        (void) DeleteImageProperty(next,"tiff:XResolution");
+      }
+    value=GetImageProperty(next,"tiff:YResolution");
+    if (value == (char *) NULL)
+      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");
+        (void) DeleteImageProperty(next,"tiff:YResolution");
+      }
+    value=GetImageProperty(next,"tiff:ResolutionUnit");
+    if (value == (char *) NULL)
+      value=GetImageProperty(next,"exif:ResolutionUnit");
+    if (value != (char *) NULL)
+      {
+        next->units=(ResolutionType) (atoi(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;
+    if (*read_info->filename != '\0')
+      {
+        char
+          *property;
+
+        const char
+          *option;
+
+        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");
+    if (profile != (const StringInfo *) NULL)
+      {
+        next->color_profile.length=GetStringInfoLength(profile);
+        next->color_profile.info=GetStringInfoDatum(profile);
+      }
+    profile=GetImageProfile(next,"iptc");
+    if (profile == (const StringInfo *) NULL)
+      profile=GetImageProfile(next,"8bim");
+    if (profile != (const StringInfo *) NULL)
+      {
+        next->iptc_profile.length=GetStringInfoLength(profile);
+        next->iptc_profile.info=GetStringInfoDatum(profile);
+      }
+    (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);
+    if (read_info->verbose != MagickFalse)
+      (void) IdentifyImage(next,stdout,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;
+
+      long
+        extent,
+        scene;
+
+      /*
+        Images of the form image-%d.png[1-5].
+      */
+      read_info=CloneImageInfo(image_info);
+      sans=AcquireExceptionInfo();
+      (void) SetImageInfo(read_info,MagickFalse,sans);
+      sans=DestroyExceptionInfo(sans);
+      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
+      images=NewImageList();
+      extent=(long) (read_info->scene+read_info->number_scenes);
+      for (scene=(long) read_info->scene; scene < (long) 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;
+
+  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);
+  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 filehandle.
+%  If writing to a file on disk, the name is defined by the filename member of
+%  the image structure.  Write() returns MagickFalse is these 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 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,MagickTrue,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,MagickTrue,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);
+      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))
+          {
+            unsigned long
+              lsb_first;
+
+            lsb_first=1;
+            image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
+         }
+    }
+  (void) SyncImageProfiles(image);
+  if ((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.
+              */
+              (void) CopyMagickString(write_info->filename,image->filename,
+                MaxTextExtent);
+              (void) AcquireUniqueFilename(image->filename);
+              temporary=MagickTrue;
+            }
+          (void) CloseBlob(image);
+        }
+    }
+  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)
+        AcquireSemaphoreInfo(&constitute_semaphore);
+      status=GetImageEncoder(magick_info)(write_info,image);
+      if ((thread_support & EncoderThreadSupport) == 0)
+        RelinquishSemaphoreInfo(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)
+            AcquireSemaphoreInfo(&constitute_semaphore);
+          status=InvokeDelegate(write_info,image,(char *) NULL,
+            write_info->magick,&image->exception);
+          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+            RelinquishSemaphoreInfo(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))
+            (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)
+                AcquireSemaphoreInfo(&constitute_semaphore);
+              status=GetImageEncoder(magick_info)(write_info,image);
+              if ((thread_support & EncoderThreadSupport) == 0)
+                RelinquishSemaphoreInfo(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) RelinquishUniqueFileResource(image->filename);
+      (void) CopyMagickString(image->filename,write_info->filename,
+        MaxTextExtent);
+      (void) CloseBlob(image);
+    }
+  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.
+%
+%  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)
+{
+  BlobInfo
+    *blob;
+
+  ExceptionInfo
+    *sans_exception;
+
+  ImageInfo
+    *write_info;
+
+  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,MagickTrue,sans_exception);
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  p=images;
+  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
+    if (p->scene >= GetNextImageInList(p)->scene)
+      {
+        register long
+          i;
+
+        /*
+          Generate consistent scene numbers.
+        */
+        i=(long) images->scene;
+        for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+          p->scene=(unsigned long) i++;
+        break;
+      }
+  /*
+    Write images.
+  */
+  status=MagickTrue;
+  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+  {
+    status&=WriteImage(write_info,p);
+    GetImageException(p,exception);
+    if (write_info->adjoin != MagickFalse)
+      break;
+  }
+  write_info=DestroyImageInfo(write_info);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
diff --git a/magick/constitute.h b/magick/constitute.h
new file mode 100644
index 0000000..7058f9f
--- /dev/null
+++ b/magick/constitute.h
@@ -0,0 +1,57 @@
+/*
+  Copyright 1999-2009 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 unsigned long,const unsigned long,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
+  WriteImage(const ImageInfo *,Image *),
+  WriteImages(const ImageInfo *,Image *,const char *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyConstitute(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/decorate.c b/magick/decorate.c
new file mode 100644
index 0000000..d89b6df
--- /dev/null
+++ b/magick/decorate.c
@@ -0,0 +1,886 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            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-2009 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 "magick/studio.h"
+#include "magick/cache-view.h"
+#include "magick/color-private.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/decorate.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/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;
+
+  /*
+    Decorate the image with a border.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(border_info != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  border_image=CloneImage(image,image->columns+2*border_info->width,
+    image->rows+2*border_info->height,MagickTrue,exception);
+  if (border_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(border_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&border_image->exception);
+      border_image=DestroyImage(border_image);
+      return((Image *) NULL);
+    }
+  border_image->background_color=border_image->border_color;
+  if (border_image->background_color.opacity != OpaqueOpacity)
+    border_image->matte=MagickTrue;
+  (void) SetImageBackgroundColor(border_image);
+  (void) CompositeImage(border_image,image->compose,image,(long)
+    border_info->width,(long) border_info->height);
+  border_image->background_color=image->background_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"
+
+  Image
+    *frame_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    accentuate,
+    border,
+    highlight,
+    interior,
+    matte,
+    shadow,
+    trough;
+
+  register long
+    x;
+
+  unsigned long
+    bevel_width,
+    height,
+    width;
+
+  CacheView
+    *frame_view;
+
+  /*
+    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=(unsigned long) (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.opacity != OpaqueOpacity)
+    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.
+  */
+  GetMagickPixelPacket(frame_image,&interior);
+  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
+    &interior);
+  GetMagickPixelPacket(frame_image,&matte);
+  matte.colorspace=RGBColorspace;
+  SetMagickPixelPacket(frame_image,&image->matte_color,(IndexPacket *) NULL,
+    &matte);
+  GetMagickPixelPacket(frame_image,&border);
+  border.colorspace=RGBColorspace;
+  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
+    &border);
+  GetMagickPixelPacket(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.opacity=matte.opacity;
+  GetMagickPixelPacket(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.opacity=matte.opacity;
+  GetMagickPixelPacket(frame_image,&shadow);
+  shadow.red=QuantumScale*matte.red*ShadowModulate;
+  shadow.green=QuantumScale*matte.green*ShadowModulate;
+  shadow.blue=QuantumScale*matte.blue*ShadowModulate;
+  shadow.opacity=matte.opacity;
+  GetMagickPixelPacket(frame_image,&trough);
+  trough.red=QuantumScale*matte.red*TroughModulate;
+  trough.green=QuantumScale*matte.green*TroughModulate;
+  trough.blue=QuantumScale*matte.blue*TroughModulate;
+  trough.opacity=matte.opacity;
+  if (image->colorspace == CMYKColorspace)
+    {
+      ConvertRGBToCMYK(&interior);
+      ConvertRGBToCMYK(&matte);
+      ConvertRGBToCMYK(&border);
+      ConvertRGBToCMYK(&accentuate);
+      ConvertRGBToCMYK(&highlight);
+      ConvertRGBToCMYK(&shadow);
+      ConvertRGBToCMYK(&trough);
+    }
+  status=MagickTrue;
+  progress=0;
+  frame_view=AcquireCacheView(frame_image);
+  height=(unsigned long) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
+    frame_info->inner_bevel);
+  if (height != 0)
+    {
+      register IndexPacket
+        *__restrict frame_indexes;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Draw top of ornamental border.
+      */
+      q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
+        height,exception);
+      frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
+      if (q != (PixelPacket *) NULL)
+        {
+          /*
+            Draw top of ornamental border.
+          */
+          for (y=0; y < (long) frame_info->outer_bevel; y++)
+          {
+            for (x=0; x < (long) (frame_image->columns-y); x++)
+            {
+              if (x < y)
+                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              else
+                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for ( ; x < (long) frame_image->columns; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          for (y=0; y < (long) (frame_info->y-bevel_width); y++)
+          {
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            width=frame_image->columns-2*frame_info->outer_bevel;
+            for (x=0; x < (long) width; x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          for (y=0; y < (long) frame_info->inner_bevel; y++)
+          {
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) (frame_info->x-bevel_width); x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            width=image->columns+((unsigned long) frame_info->inner_bevel << 1)-
+              y;
+            for (x=0; x < (long) width; x++)
+            {
+              if (x < y)
+                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              else
+                SetPixelPacket(frame_image,&trough,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for ( ; x < (long) (image->columns+2*frame_info->inner_bevel); x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            width=frame_info->width-frame_info->x-image->columns-bevel_width;
+            for (x=0; x < (long) width; x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
+        }
+    }
+  /*
+    Draw sides of ornamental border.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict frame_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
+    for (x=0; x < (long) frame_info->outer_bevel; x++)
+    {
+      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    for (x=0; x < (long) (frame_info->x-bevel_width); x++)
+    {
+      SetPixelPacket(frame_image,&matte,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    for (x=0; x < (long) frame_info->inner_bevel; x++)
+    {
+      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    /*
+      Set frame interior to interior color.
+    */
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetPixelPacket(frame_image,&interior,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    for (x=0; x < (long) frame_info->inner_bevel; x++)
+    {
+      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    width=frame_info->width-frame_info->x-image->columns-bevel_width;
+    for (x=0; x < (long) width; x++)
+    {
+      SetPixelPacket(frame_image,&matte,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    for (x=0; x < (long) frame_info->outer_bevel; x++)
+    {
+      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+      q++;
+      frame_indexes++;
+    }
+    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=(unsigned long) (frame_info->inner_bevel+frame_info->height-
+    frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
+  if (height != 0)
+    {
+      register IndexPacket
+        *__restrict frame_indexes;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Draw bottom of ornamental border.
+      */
+      q=QueueCacheViewAuthenticPixels(frame_view,0,(long) (frame_image->rows-
+        height),frame_image->columns,height,exception);
+      if (q != (PixelPacket *) NULL)
+        {
+          /*
+            Draw bottom of ornamental border.
+          */
+          frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
+          for (y=frame_info->inner_bevel-1; y >= 0; y--)
+          {
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) (frame_info->x-bevel_width); x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < y; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for ( ; x < (long) (image->columns+2*frame_info->inner_bevel); x++)
+            {
+              if (x >= (long) (image->columns+2*frame_info->inner_bevel-y))
+                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              else
+                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            width=frame_info->width-frame_info->x-image->columns-bevel_width;
+            for (x=0; x < (long) width; x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          height=frame_info->height-frame_info->y-image->rows-bevel_width;
+          for (y=0; y < (long) height; y++)
+          {
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            width=frame_image->columns-2*frame_info->outer_bevel;
+            for (x=0; x < (long) width; x++)
+            {
+              SetPixelPacket(frame_image,&matte,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for (x=0; x < (long) frame_info->outer_bevel; x++)
+            {
+              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          for (y=frame_info->outer_bevel-1; y >= 0; y--)
+          {
+            for (x=0; x < y; x++)
+            {
+              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+            for ( ; x < (long) frame_image->columns; x++)
+            {
+              if (x >= (long) (frame_image->columns-y))
+                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
+              else
+                SetPixelPacket(frame_image,&trough,q,frame_indexes);
+              q++;
+              frame_indexes++;
+            }
+          }
+          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
+        }
+    }
+  frame_view=DestroyCacheView(frame_view);
+  x=(long) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
+    frame_info->inner_bevel);
+  y=(long) (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)
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  Quantum
+    foreground,
+    background;
+
+  CacheView
+    *image_view;
+
+  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)
+#endif
+  for (y=0; y < (long) raise_info->height; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < y; x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q++;
+    }
+    for ( ; x < (long) (image->columns-y); x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*
+        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
+        AccentuateFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
+        AccentuateFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
+        AccentuateFactor)));
+      q++;
+    }
+    for ( ; x < (long) image->columns; x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
+        (MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q++;
+    }
+    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)
+#endif
+  for (y=(long) raise_info->height; y < (long) (image->rows-raise_info->height); y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) raise_info->width; x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q++;
+    }
+    for ( ; x < (long) (image->columns-raise_info->width); x++)
+      q++;
+    for ( ; x < (long) image->columns; x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
+        (MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q++;
+    }
+    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)
+#endif
+  for (y=(long) (image->rows-raise_info->height); y < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) (image->rows-y); x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
+        HighlightFactor)));
+      q++;
+    }
+    for ( ; x < (long) (image->columns-(image->rows-y)); x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*TroughFactor+
+        (MagickRealType) background*(QuantumRange-TroughFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        TroughFactor+(MagickRealType) background*(QuantumRange-TroughFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        TroughFactor+(MagickRealType) background*(QuantumRange-TroughFactor)));
+      q++;
+    }
+    for ( ; x < (long) image->columns; x++)
+    {
+      q->red=RoundToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
+        (MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->green=RoundToQuantum(QuantumScale*((MagickRealType) q->green*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      q->blue=RoundToQuantum(QuantumScale*((MagickRealType) q->blue*
+        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
+      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_RaiseImage)
+#endif
+        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/magick/decorate.h b/magick/decorate.h
new file mode 100644
index 0000000..194e274
--- /dev/null
+++ b/magick/decorate.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2009 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
+
+typedef struct _FrameInfo
+{
+  unsigned long
+    width,
+    height;
+
+  long
+    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/magick/delegate-private.h b/magick/delegate-private.h
new file mode 100644
index 0000000..e0994c0
--- /dev/null
+++ b/magick/delegate-private.h
@@ -0,0 +1,66 @@
+/*
+  Copyright 1999-2009 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(__WINDOWS__)
+#    define MagickDLLCall __stdcall
+#  else
+#    define MagickDLLCall
+#  endif
+#endif
+
+typedef struct _GhostscriptVectors
+{
+  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 *);
+} GhostscriptVectors;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/delegate.c b/magick/delegate.c
new file mode 100644
index 0000000..b9f9a94
--- /dev/null
+++ b/magick/delegate.c
@@ -0,0 +1,1468 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/policy.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/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=\"hdr\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&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=\"pic\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&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=pam&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=\"rad\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&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\" 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=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"svg\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&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 s t r o y D e l e g a t e L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyDelegateList() deallocates memory associated with the delegates list.
+%
+%  The format of the DestroyDelegateList method is:
+%
+%      DestroyDelegateList(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 DestroyDelegateList(void)
+{
+  AcquireSemaphoreInfo(&delegate_semaphore);
+  if (delegate_list != (LinkedListInfo *) NULL)
+    delegate_list=DestroyLinkedList(delegate_list,DestroyDelegate);
+  instantiate_delegate=MagickFalse;
+  RelinquishSemaphoreInfo(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 long
+    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.
+  */
+  AcquireSemaphoreInfo(&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));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_delegates,ExceptionInfo *exception)
+{
+  const DelegateInfo
+    **delegates;
+
+  register const DelegateInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate delegate list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_delegates != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(delegate_semaphore);
+  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
+  delegates[i]=(DelegateInfo *) NULL;
+  *number_delegates=(unsigned long) 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,
+%        unsigned long *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,
+  unsigned long *number_delegates,ExceptionInfo *exception)
+{
+  char
+    **delegates;
+
+  register const DelegateInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate delegate list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_delegates != (unsigned long *) 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);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(delegate_semaphore);
+  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
+  delegates[i]=(char *) NULL;
+  *number_delegates=(unsigned long) 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:
+%
+%      long GetDelegateMode(const DelegateInfo *delegate_info)
+%
+%  A description of each parameter follows:
+%
+%    o delegate_info:  The delegate info.
+%
+*/
+MagickExport long 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))
+    {
+      AcquireSemaphoreInfo(&delegate_semaphore);
+      if ((delegate_list == (LinkedListInfo *) NULL) &&
+          (instantiate_delegate == MagickFalse))
+        {
+          (void) LoadDelegateLists(DelegateFilename,exception);
+          instantiate_delegate=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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 long
+    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)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",decode);
+      return(MagickFalse);
+    }
+  if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
+    {
+      (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) FormatMagickString(clone_info->filename,MaxTextExtent,"%s:",
+        delegate_info->decode);
+      (void) SetImageInfo(clone_info,MagickTrue,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) FormatMagickString(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.
+        */
+        if (delegate_info->spawn != MagickFalse)
+          (void) ConcatenateString(&command," &");
+        status=SystemCommand(image_info->verbose,command) != 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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_delegates;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",delegate_info[i]->path);
+        (void) fprintf(file,"Delegate                Command\n");
+        (void) fprintf(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) fprintf(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) fprintf(file,"\"%s\"\n",commands[0]);
+    for (j=1; commands[j] != (char *) NULL; j++)
+    {
+      StripString(commands[j]);
+      (void) fprintf(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 unsigned long 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 unsigned long 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(__WINDOWS__)
+            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/magick/delegate.h b/magick/delegate.h
new file mode 100644
index 0000000..16061fb
--- /dev/null
+++ b/magick/delegate.h
@@ -0,0 +1,76 @@
+/*
+  Copyright 1999-2009 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;
+                                                                                
+  long
+    mode;
+                                                                                
+  MagickBooleanType
+    thread_support,
+    spawn,
+    stealth;
+                                                                                
+  struct _DelegateInfo
+    *previous,
+    *next;  /* deprecated, use GetDelegateInfoList() */
+
+  unsigned long
+    signature;
+} DelegateInfo;
+
+extern MagickExport char
+  *GetDelegateCommand(const ImageInfo *,Image *,const char *,const char *,
+    ExceptionInfo *),
+  **GetDelegateList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetDelegateCommands(const DelegateInfo *);
+
+extern MagickExport const DelegateInfo
+  *GetDelegateInfo(const char *,const char *,ExceptionInfo *exception),
+  **GetDelegateInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport long
+  GetDelegateMode(const DelegateInfo *);
+
+extern MagickExport MagickBooleanType
+  GetDelegateThreadSupport(const DelegateInfo *),
+  InvokeDelegate(ImageInfo *,Image *,const char *,const char *,ExceptionInfo *),
+  ListDelegateInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyDelegateList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/deprecate.c b/magick/deprecate.c
new file mode 100644
index 0000000..7874b71
--- /dev/null
+++ b/magick/deprecate.c
@@ -0,0 +1,6344 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/deprecate.h"
+#include "magick/draw.h"
+#include "magick/draw-private.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/identify.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/magick.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/paint.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/quantize.h"
+#include "magick/random_.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/segment.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/threshold.h"
+#include "magick/transform.h"
+#include "magick/utility.h"
+
+#if !defined(MAGICKCORE_EXCLUDE_DEPRECATED)
+/*
+  Global declarations.
+*/
+static MonitorHandler
+  monitor_handler = (MonitorHandler) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e C a c h e V i e w I n d e x e s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireCacheViewIndexes() returns the indexes associated with the specified
+%  view.
+%
+%  The format of the AcquireCacheViewIndexes method is:
+%
+%      const IndexPacket *AcquireCacheViewIndexes(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport const IndexPacket *AcquireCacheViewIndexes(
+  const CacheView *cache_view)
+{
+  return(GetCacheViewVirtualIndexQueue(cache_view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e C a c h e V i e w P i x e l s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireCacheViewPixels() 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 AcquireCacheViewPixels method is:
+%
+%      const PixelPacket *AcquireCacheViewPixels(const CacheView *cache_view,
+%        const long x,const long y,const unsigned long columns,
+%        const unsigned long 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 PixelPacket *AcquireCacheViewPixels(
+  const CacheView *cache_view,const long x,const long y,
+  const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
+{
+  return(GetCacheViewVirtualPixels(cache_view,x,y,columns,rows,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e I m a g e P i x e l s                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireImagePixels() 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 RAM, or in a memory-mapped file.  The
+%  returned pointer should *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access the
+%  black color component or to obtain the colormap indexes (of type IndexPacket)
+%  corresponding to the region.
+%
+%  If you plan to modify the pixels, use GetAuthenticPixels() instead.
+%
+%  Note, the AcquireImagePixels() and GetAuthenticPixels() methods are not
+%  thread-safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
+%  GetCacheViewAuthenticPixels() instead.
+%
+%  The format of the AcquireImagePixels() method is:
+%
+%      const PixelPacket *AcquireImagePixels(const Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *AcquireImagePixels(const Image *image,
+  const long x,const long y,const unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+  return(GetVirtualPixels(image,x,y,columns,rows,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e I n d e x e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireIndexes() returns the black channel or the colormap indexes
+%  associated with the last call to QueueAuthenticPixels() or GetVirtualPixels().
+%  NULL is returned if the black channel or colormap indexes are not available.
+%
+%  The format of the AcquireIndexes() method is:
+%
+%      const IndexPacket *AcquireIndexes(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o indexes: AcquireIndexes() returns the indexes associated with the last
+%      call to QueueAuthenticPixels() or GetVirtualPixels().
+%
+%    o image: the image.
+%
+*/
+MagickExport const IndexPacket *AcquireIndexes(const Image *image)
+{
+  return(GetVirtualIndexQueue(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e M e m o r y                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireMemory() returns a pointer to a block of memory at least size bytes
+%  suitably aligned for any use.
+%
+%  The format of the AcquireMemory method is:
+%
+%      void *AcquireMemory(const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o size: the size of the memory in bytes to allocate.
+%
+*/
+MagickExport void *AcquireMemory(const size_t size)
+{
+  void
+    *allocation;
+
+  assert(size != 0);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  allocation=malloc(size);
+  return(allocation);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e O n e C a c h e V i e w P i x e l                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireOneCacheViewPixel() 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 AcquireOneCacheViewPixel method is:
+%
+%      MagickBooleanType AcquireOneCacheViewPixel(const CacheView *cache_view,
+%        const long x,const long 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 AcquireOneCacheViewPixel(
+  const CacheView *cache_view,const long x,const long y,PixelPacket *pixel,
+  ExceptionInfo *exception)
+{
+  return(GetOneCacheViewVirtualPixel(cache_view,x,y,pixel,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e O n e C a c h e V i e w V i r t u a l P i x e l             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireOneCacheViewVirtualPixel() 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 AcquireOneCacheViewPixel method is:
+%
+%      MagickBooleanType AcquireOneCacheViewVirtualPixel(
+%        const CacheView *cache_view,
+%        const VirtualPixelMethod virtual_pixel_method,const long x,
+%        const long 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 AcquireOneCacheViewVirtualPixel(
+  const CacheView *cache_view,const VirtualPixelMethod virtual_pixel_method,
+  const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetOneCacheViewVirtualMethodPixel(cache_view,virtual_pixel_method,
+    x,y,pixel,exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e O n e M a g i c k P i x e l                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireOneMagickPixel() 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 GetOnePixel() instead.
+%
+%  The format of the AcquireOneMagickPixel() method is:
+%
+%      MagickPixelPacket AcquireOneMagickPixel(const Image image,const long x,
+%        const long y,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 exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickPixelPacket AcquireOneMagickPixel(const Image *image,
+  const long x,const long y,ExceptionInfo *exception)
+{
+  MagickPixelPacket
+    pixel;
+
+  (void) GetOneVirtualMagickPixel(image,x,y,&pixel,exception);
+  return(pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e O n e P i x e l                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireOnePixel() 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 GetOnePixel() instead.
+%
+%  The format of the AcquireOnePixel() method is:
+%
+%      PixelPacket AcquireOnePixel(const Image image,const long x,
+%        const long y,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 exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport PixelPacket AcquireOnePixel(const Image *image,const long x,
+  const long y,ExceptionInfo *exception)
+{
+  PixelPacket
+    pixel;
+
+  (void) GetOneVirtualPixel(image,x,y,&pixel,exception);
+  return(pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e O n e V i r t u a l P i x e l                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireOneVirtualPixel() 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
+%  GetOnePixel() instead.
+%
+%  The format of the AcquireOneVirtualPixel() method is:
+%
+%      PixelPacket AcquireOneVirtualPixel(const Image image,
+%        const VirtualPixelMethod virtual_pixel_method,const long x,
+%        const long y,ExceptionInfo exception)
+%
+%  A description of each parameter follows:
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o image: the image.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport PixelPacket AcquireOneVirtualPixel(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
+  ExceptionInfo *exception)
+{
+  PixelPacket
+    pixel;
+
+  (void) GetOneVirtualMethodPixel(image,virtual_pixel_method,x,y,&pixel,
+    exception);
+  return(pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e P i x e l s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquirePixels() returns the pixels associated with the last call to
+%  QueueAuthenticPixels() or GetVirtualPixels().
+%
+%  The format of the AcquirePixels() method is:
+%
+%      const PixelPacket *AcquirePixels(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const PixelPacket *AcquirePixels(const Image *image)
+{
+  return(GetVirtualPixelQueue(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A f f i n i t y I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AffinityImage() replaces the colors of an image with the closest color from
+%  a reference image.
+%
+%  The format of the AffinityImage method is:
+%
+%      MagickBooleanType AffinityImage(const QuantizeInfo *quantize_info,
+%        Image *image,const Image *affinity_image)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o image: the image.
+%
+%    o affinity_image: the reference image.
+%
+*/
+MagickExport MagickBooleanType AffinityImage(const QuantizeInfo *quantize_info,
+  Image *image,const Image *affinity_image)
+{
+  return(RemapImage(quantize_info,image,affinity_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A f f i n i t y I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AffinityImages() replaces the colors of a sequence of images with the
+%  closest color from a reference image.
+%
+%  The format of the AffinityImage method is:
+%
+%      MagickBooleanType AffinityImages(const QuantizeInfo *quantize_info,
+%        Image *images,Image *affinity_image)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o images: the image sequence.
+%
+%    o affinity_image: the reference image.
+%
+*/
+MagickExport MagickBooleanType AffinityImages(const QuantizeInfo *quantize_info,
+  Image *images,const Image *affinity_image)
+{
+  return(RemapImages(quantize_info,images,affinity_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A l l o c a t e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AllocateImage() returns a pointer to an image structure initialized to
+%  default values.
+%
+%  The format of the AllocateImage method is:
+%
+%      Image *AllocateImage(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 *AllocateImage(const ImageInfo *image_info)
+{
+  return(AcquireImage(image_info));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A l l o c a t e I m a g e C o l o r m a p                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AllocateImageColormap() allocates an image colormap and initializes
+%  it to a linear gray colorspace.  If the image already has a colormap,
+%  it is replaced.  AllocateImageColormap() returns MagickTrue if successful,
+%  otherwise MagickFalse if there is not enough memory.
+%
+%  The format of the AllocateImageColormap method is:
+%
+%      MagickBooleanType AllocateImageColormap(Image *image,
+%        const unsigned long colors)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colors: the number of colors in the image colormap.
+%
+*/
+MagickExport MagickBooleanType AllocateImageColormap(Image *image,
+  const unsigned long colors)
+{
+  return(AcquireImageColormap(image,colors));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A l l o c a t e N e x t I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AllocateNextImage() 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 AllocateNextImage method is:
+%
+%      void AllocateNextImage(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 AllocateNextImage(const ImageInfo *image_info,Image *image)
+{
+  AcquireNextImage(image_info,image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e S t r i n g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AllocateString() allocates memory for a string and copies the source string
+%  to that memory location (and returns it).
+%
+%  The format of the AllocateString method is:
+%
+%      char *AllocateString(const char *source)
+%
+%  A description of each parameter follows:
+%
+%    o source: A character string.
+%
+*/
+MagickExport char *AllocateString(const char *source)
+{
+  char
+    *destination;
+
+  size_t
+    length;
+
+  assert(source != (const char *) NULL);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  length=strlen(source)+MaxTextExtent+1;
+  destination=(char *) AcquireQuantumMemory(length,sizeof(*destination));
+  if (destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  *destination='\0';
+  if (source != (char *) NULL)
+    (void) CopyMagickString(destination,source,length);
+  return(destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C h a n n e l I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Extract a channel from the image.  A channel is a particular color component
+%  of each pixel in the image.
+%
+%  The format of the ChannelImage method is:
+%
+%      unsigned int ChannelImage(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, OpacityChannel, CyanChannel, MagentaChannel, YellowChannel,
+%      or BlackChannel.
+%
+*/
+MagickExport unsigned int ChannelImage(Image *image,const ChannelType channel)
+{
+  return(SeparateImageChannel(image,channel));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C h a n n e l T h r e s h o l d I m a g e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ChannelThresholdImage() changes the value of individual pixels based on
+%  the intensity of each pixel channel.  The result is a high-contrast image.
+%
+%  The format of the ChannelThresholdImage method is:
+%
+%      unsigned int ChannelThresholdImage(Image *image,const char *level)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o level: define the threshold values.
+%
+*/
+MagickExport unsigned int ChannelThresholdImage(Image *image,const char *level)
+{
+  MagickPixelPacket
+    threshold;
+
+  GeometryInfo
+    geometry_info;
+
+  unsigned int
+    flags,
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (level == (char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(level,&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;
+  status=BilevelImageChannel(image,RedChannel,threshold.red);
+  status|=BilevelImageChannel(image,GreenChannel,threshold.green);
+  status|=BilevelImageChannel(image,BlueChannel,threshold.blue);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l i p I m a g e P a t h                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClipPathImage() sets the image clip mask based any clipping path information
+%  if it exists.
+%
+%  The format of the ClipImage method is:
+%
+%      MagickBooleanType ClipPathImage(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 ClipPathImage(Image *image,const char *pathname,
+  const MagickBooleanType inside)
+{
+  return(ClipImagePath(image,pathname,inside));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e A t t r i b u t e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageAttributes() clones one or more image attributes.
+%
+%  The format of the CloneImageAttributes method is:
+%
+%      MagickBooleanType CloneImageAttributes(Image *image,
+%        const Image *clone_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clone_image: the clone image.
+%
+*/
+MagickExport MagickBooleanType CloneImageAttributes(Image *image,
+  const Image *clone_image)
+{
+  return(CloneImageProperties(image,clone_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e M e m o r y                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneMemory() 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 CloneMemory method is:
+%
+%      void *CloneMemory(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 *CloneMemory(void *destination,const void *source,
+  const size_t size)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned char
+    *q;
+
+  register long
+    i;
+
+  assert(destination != (void *) NULL);
+  assert(source != (const void *) NULL);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  p=(const unsigned char *) source;
+  q=(unsigned char *) destination;
+  if ((p <= q) || ((p+size) >= q))
+    return(CopyMagickMemory(destination,source,size));
+  /*
+    Overlap, copy backwards.
+  */
+  p+=size;
+  q+=size;
+  for (i=(long) (size-1); i >= 0; i--)
+    *--q=(*--p);
+  return(destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o s e C a c h e V i e w                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloseCacheView() closes the specified view returned by a previous call to
+%  OpenCacheView().
+%
+%  The format of the CloseCacheView method is:
+%
+%      CacheView *CloseCacheView(CacheView *view_info)
+%
+%  A description of each parameter follows:
+%
+%    o view_info: the address of a structure of type CacheView.
+%
+*/
+MagickExport CacheView *CloseCacheView(CacheView *view_info)
+{
+  return(DestroyCacheView(view_info));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o l o r F l o o d f i l l I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorFloodfill() 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 ColorFloodfillImage method is:
+%
+%      MagickBooleanType ColorFloodfillImage(Image *image,
+%        const DrawInfo *draw_info,const PixelPacket target,
+%        const long x_offset,const long y_offset,const PaintMethod method)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o target: the RGB value of the target color.
+%
+%    o x,y: the starting location of the operation.
+%
+%    o method: Choose either FloodfillMethod or FillToBorderMethod.
+%
+*/
+
+#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)) < (long) image->rows)) \
+        { \
+          s->x1=(double) (left); \
+          s->y1=(double) (up); \
+          s->x2=(double) (right); \
+          s->y2=(double) (delta); \
+          s++; \
+        } \
+    } \
+}
+
+MagickExport MagickBooleanType ColorFloodfillImage(Image *image,
+  const DrawInfo *draw_info,const PixelPacket target,const long x_offset,
+  const long y_offset,const PaintMethod method)
+{
+  Image
+    *floodplane_image;
+
+  long
+    offset,
+    start,
+    x,
+    x1,
+    x2,
+    y;
+
+  MagickBooleanType
+    skip;
+
+  PixelPacket
+    fill_color;
+
+  register SegmentInfo
+    *s;
+
+  SegmentInfo
+    *segment_stack;
+
+  /*
+    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 >= (long) image->columns))
+    return(MagickFalse);
+  if ((y_offset < 0) || (y_offset >= (long) image->rows))
+    return(MagickFalse);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    &image->exception);
+  if (floodplane_image == (Image *) NULL)
+    return(MagickFalse);
+  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
+  /*
+    Set floodfill color.
+  */
+  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.
+  */
+  x=x_offset;
+  y=y_offset;
+  start=0;
+  s=segment_stack;
+  PushSegmentStack(y,x,x,1);
+  PushSegmentStack(y+1,x,x,-1);
+  while (s > segment_stack)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Pop segment off stack.
+    */
+    s--;
+    x1=(long) s->x1;
+    x2=(long) s->x2;
+    offset=(long) s->y2;
+    y=(long) s->y1+offset;
+    /*
+      Recolor neighboring pixels.
+    */
+    p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,&image->exception);
+    q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1,
+      &image->exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    p+=x1;
+    q+=x1;
+    for (x=x1; x >= 0; x--)
+    {
+      if (q->opacity == (Quantum) TransparentOpacity)
+        break;
+      if (method == FloodfillMethod)
+        {
+          if (IsColorSimilar(image,p,&target) == MagickFalse)
+            break;
+        }
+      else
+        if (IsColorSimilar(image,p,&target) != MagickFalse)
+          break;
+      q->opacity=(Quantum) TransparentOpacity;
+      p--;
+      q--;
+    }
+    if (SyncAuthenticPixels(floodplane_image,&image->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 < (long) image->columns)
+            {
+              p=GetVirtualPixels(image,x,y,image->columns-x,1,
+                &image->exception);
+              q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1,
+                &image->exception);
+              if ((p == (const PixelPacket *) NULL) ||
+                  (q == (PixelPacket *) NULL))
+                break;
+              for ( ; x < (long) image->columns; x++)
+              {
+                if (q->opacity == (Quantum) TransparentOpacity)
+                  break;
+                if (method == FloodfillMethod)
+                  {
+                    if (IsColorSimilar(image,p,&target) == MagickFalse)
+                      break;
+                  }
+                else
+                  if (IsColorSimilar(image,p,&target) != MagickFalse)
+                    break;
+                q->opacity=(Quantum) TransparentOpacity;
+                p++;
+                q++;
+              }
+              if (SyncAuthenticPixels(floodplane_image,&image->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=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,
+            &image->exception);
+          q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1,
+            &image->exception);
+          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+            break;
+          for ( ; x <= x2; x++)
+          {
+            if (q->opacity == (Quantum) TransparentOpacity)
+              break;
+            if (method == FloodfillMethod)
+              {
+                if (IsColorSimilar(image,p,&target) != MagickFalse)
+                  break;
+              }
+            else
+              if (IsColorSimilar(image,p,&target) == MagickFalse)
+                break;
+            p++;
+            q++;
+          }
+        }
+      start=x;
+    } while (x <= x2);
+  }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Tile fill color onto floodplane.
+    */
+    p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,
+      &image->exception);
+    q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (p->opacity != OpaqueOpacity)
+        {
+          (void) GetFillColor(draw_info,x,y,&fill_color);
+          MagickCompositeOver(&fill_color,(MagickRealType) fill_color.opacity,q,
+            (MagickRealType) q->opacity,q);
+        }
+      p++;
+      q++;
+    }
+    if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+      break;
+  }
+  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
+  floodplane_image=DestroyImage(floodplane_image);
+  return(y == (long) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e A t t r i b u t e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageAttribute() deletes an attribute from the image.
+%
+%  The format of the DeleteImageAttribute method is:
+%
+%      MagickBooleanType DeleteImageAttribute(Image *image,const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image info.
+%
+%    o key: the image key.
+%
+*/
+MagickExport MagickBooleanType DeleteImageAttribute(Image *image,
+  const char *key)
+{
+  return(DeleteImageProperty(image,key));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageList() deletes an image at the specified position in the list.
+%
+%  The format of the DeleteImageList method is:
+%
+%      unsigned int DeleteImageList(Image *images,const long offset)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o offset: the position within the list.
+%
+*/
+MagickExport unsigned int DeleteImageList(Image *images,const long offset)
+{
+  register long
+    i;
+
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  while (GetPreviousImageInList(images) != (Image *) NULL)
+    images=GetPreviousImageInList(images);
+  for (i=0; i < offset; i++)
+  {
+    if (GetNextImageInList(images) == (Image *) NULL)
+      return(MagickFalse);
+    images=GetNextImageInList(images);
+  }
+  DeleteImageFromList(&images);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e M a g i c k R e g i s t r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteMagickRegistry() deletes an entry in the registry as defined by the id.
+%  It returns MagickTrue if the entry is deleted otherwise MagickFalse if no
+%  entry is found in the registry that matches the id.
+%
+%  The format of the DeleteMagickRegistry method is:
+%
+%      MagickBooleanType DeleteMagickRegistry(const long id)
+%
+%  A description of each parameter follows:
+%
+%    o id: the registry id.
+%
+*/
+MagickExport MagickBooleanType DeleteMagickRegistry(const long id)
+{
+  char
+    key[MaxTextExtent];
+
+  (void) FormatMagickString(key,MaxTextExtent,"%ld\n",id);
+  return(DeleteImageRegistry(key));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M a g i c k R e g i s t r y                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagickRegistry() deallocates memory associated the magick registry.
+%
+%  The format of the DestroyMagickRegistry method is:
+%
+%       void DestroyMagickRegistry(void)
+%
+*/
+MagickExport void DestroyMagickRegistry(void)
+{
+  DestroyImageRegistry();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s c r i b e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DescribeImage() describes an image by printing its attributes to the file.
+%  Attributes include the image width, height, size, and others.
+%
+%  The format of the DescribeImage method is:
+%
+%      MagickBooleanType DescribeImage(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.
+%
+*/
+MagickExport MagickBooleanType DescribeImage(Image *image,FILE *file,
+  const MagickBooleanType verbose)
+{
+  return(IdentifyImage(image,file,verbose));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e A t t r i b u t e s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageAttributes() deallocates memory associated with the image
+%  attribute list.
+%
+%  The format of the DestroyImageAttributes method is:
+%
+%      DestroyImageAttributes(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyImageAttributes(Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->attributes != (void *) NULL)
+    image->attributes=(void *) DestroySplayTree((SplayTreeInfo *)
+      image->attributes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImages() destroys an image list.
+%
+%  The format of the DestroyImages method is:
+%
+%      void DestroyImages(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence.
+%
+*/
+MagickExport void DestroyImages(Image *image)
+{
+  if (image == (Image *) NULL)
+    return;
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.4.3");
+  image=DestroyImageList(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y M a g i c k                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagick() destroys the ImageMagick environment.
+%
+%  The format of the DestroyMagick function is:
+%
+%      DestroyMagick(void)
+%
+*/
+MagickExport void DestroyMagick(void)
+{
+  MagickCoreTerminus();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D i s p a t c h I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DispatchImage() extracts pixel data from an image and returns it to you.
+%  The method returns MagickFalse on success otherwise MagickTrue if an error is
+%  encountered.  The data is returned as char, short int, int, long, 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:
+%
+%      DispatchImage(image,0,0,640,1,"RGB",CharPixel,pixels,exception);
+%
+%  The format of the DispatchImage method is:
+%
+%      unsigned int DispatchImage(const Image *image,const long x_offset,
+%        const long y_offset,const unsigned long columns,
+%        const unsigned long 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, C = cyan, Y = yellow, M = magenta, K = black, or
+%      I = intensity (for grayscale).
+%
+%    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.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned int DispatchImage(const Image *image,const long x_offset,
+  const long y_offset,const unsigned long columns,const unsigned long rows,
+  const char *map,const StorageType type,void *pixels,ExceptionInfo *exception)
+{
+  unsigned int
+    status;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.6");
+  status=ExportImagePixels(image,x_offset,y_offset,columns,rows,map,type,pixels,
+    exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x t r a c t S u b i m a g e F r o m I m a g e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExtractSubimageFromImageImage() extracts a region of the image that most
+%  closely resembles the referemce.
+%
+%  The format of the ExtractSubimageFromImageImage method is:
+%
+%      Image *ExtractSubimageFromImage(const Image *image,const Image *referemce,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o referemce: find an area of the image that closely resembles this image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static double GetSimilarityMetric(const Image *image,const Image *referemce,
+  const long x_offset,const long y_offset,const double similarity_threshold,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  double
+    channels,
+    normalized_similarity,
+    similarity;
+
+  CacheView
+    *image_view,
+    *referemce_view;
+
+  /*
+    Compute the similarity in pixels between two images.
+  */
+  normalized_similarity=1.0;
+  similarity=0.0;
+  channels=3;
+  if ((image->matte != MagickFalse) && (referemce->matte != MagickFalse))
+    channels++;
+  if ((image->colorspace == CMYKColorspace) &&
+      (referemce->colorspace == CMYKColorspace))
+    channels++;
+  image_view=AcquireCacheView(image);
+  referemce_view=AcquireCacheView(referemce);
+  for (y=0; y < (long) referemce->rows; y++)
+  {
+    register const IndexPacket
+      *indexes,
+      *referemce_indexes;
+
+    register const PixelPacket
+      *p,
+      *q;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset+y,
+      referemce->columns,1,exception);
+    q=GetCacheViewVirtualPixels(referemce_view,0,y,referemce->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      continue;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    referemce_indexes=GetCacheViewVirtualIndexQueue(referemce_view);
+    for (x=0; x < (long) referemce->columns; x++)
+    {
+      MagickRealType
+        pixel;
+
+      pixel=QuantumScale*(p->red-(double) q->red);
+      similarity+=pixel*pixel;
+      pixel=QuantumScale*(p->green-(double) q->green);
+      similarity+=pixel*pixel;
+      pixel=QuantumScale*(p->blue-(double) q->blue);
+      similarity+=pixel*pixel;
+      if ((image->matte != MagickFalse) && (referemce->matte != MagickFalse))
+        {
+          pixel=QuantumScale*(p->opacity-(double) q->opacity);
+          similarity+=pixel*pixel;
+        }
+      if ((image->colorspace == CMYKColorspace) &&
+          (referemce->colorspace == CMYKColorspace))
+        {
+          pixel=QuantumScale*(indexes[x]-(double) referemce_indexes[x]);
+          similarity+=pixel*pixel;
+        }
+      p++;
+      q++;
+    }
+    normalized_similarity=sqrt(similarity)/referemce->columns/referemce->rows/
+      channels;
+    if (normalized_similarity > similarity_threshold)
+      break;
+  }
+  referemce_view=DestroyCacheView(referemce_view);
+  image_view=DestroyCacheView(image_view);
+  return(normalized_similarity);
+}
+
+MagickExport Image *ExtractSubimageFromImage(Image *image,const Image *referemce,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  double
+    similarity_threshold;
+
+  RectangleInfo
+    offset;
+
+  /*
+    Extract referemce from image.
+  */
+  if ((referemce->columns > image->columns) || (referemce->rows > image->rows))
+    return((Image *) NULL);
+  similarity_threshold=HUGE_VAL;
+  SetGeometry(referemce,&offset);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+  for (y=0; y < (long) (image->rows-referemce->rows); y++)
+  {
+    double
+      similarity;
+
+    register long
+      x;
+
+    for (x=0; x < (long) (image->columns-referemce->columns); x++)
+    {
+      similarity=GetSimilarityMetric(image,referemce,x,y,similarity_threshold,
+        exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ExtractSubimageFromImage)
+#endif
+      if (similarity < similarity_threshold)
+        {
+          similarity_threshold=similarity;
+          offset.x=x;
+          offset.y=y;
+        }
+    }
+  }
+  if (similarity_threshold > (QuantumScale*referemce->fuzz/100.0))
+    return((Image *) NULL);
+  return(CropImage(image,&offset,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     F l a t t e n I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FlattenImages() Obsolete Function: Use MergeImageLayers() instead.
+%
+%  The format of the FlattenImage method is:
+%
+%      Image *FlattenImage(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 *FlattenImages(Image *image,ExceptionInfo *exception)
+{
+  return(MergeImageLayers(image,FlattenLayer,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t I m a g e A t t r i b u t e                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatImageAttribute() permits formatted key/value pairs to be saved as an
+%  image attribute.
+%
+%  The format of the FormatImageAttribute method is:
+%
+%      MagickBooleanType FormatImageAttribute(Image *image,const char *key,
+%        const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o  image:  The image.
+%
+%   o  key:  The attribute key.
+%
+%   o  format:  A string describing the format to use to write the remaining
+%      arguments.
+%
+*/
+
+MagickExport MagickBooleanType FormatImageAttributeList(Image *image,
+  const char *key,const char *format,va_list operands)
+{
+  char
+    value[MaxTextExtent];
+
+  int
+    n;
+
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(value,MaxTextExtent,format,operands);
+#else
+  n=vsprintf(value,format,operands);
+#endif
+  if (n < 0)
+    value[MaxTextExtent-1]='\0';
+  return(SetImageAttribute(image,key,value));
+}
+
+MagickExport MagickBooleanType FormatImageAttribute(Image *image,
+  const char *key,const char *format,...)
+{
+  MagickBooleanType
+    status;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  status=FormatImageAttributeList(image,key,format,operands);
+  va_end(operands);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t S t r i n g                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatString() prints formatted output of a variable argument list.
+%
+%  The format of the FormatString method is:
+%
+%      void FormatString(char *string,const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o  string:  Method FormatString returns the formatted string in this
+%      character buffer.
+%
+%   o  format:  A string describing the format to use to write the remaining
+%      arguments.
+%
+*/
+
+MagickExport void FormatStringList(char *string,const char *format,
+  va_list operands)
+{
+  int
+    n;
+
+ (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(string,MaxTextExtent,format,operands);
+#else
+  n=vsprintf(string,format,operands);
+#endif
+  if (n < 0)
+    string[MaxTextExtent-1]='\0';
+}
+
+MagickExport void FormatString(char *string,const char *format,...)
+{
+  va_list
+    operands;
+
+  va_start(operands,format);
+  FormatStringList(string,format,operands);
+  va_end(operands);
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F u z z y C o l o r M a t c h                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FuzzyColorMatch() returns true if two pixels are identical in color.
+%
+%  The format of the ColorMatch method is:
+%
+%      void FuzzyColorMatch(const PixelPacket *p,const PixelPacket *q,
+%        const double fuzz)
+%
+%  A description of each parameter follows:
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+%    o distance:  Define how much tolerance is acceptable to consider
+%      two colors as the same.
+%
+*/
+MagickExport unsigned int FuzzyColorMatch(const PixelPacket *p,
+  const PixelPacket *q,const double fuzz)
+{
+  MagickPixelPacket
+    pixel;
+
+  register MagickRealType
+    distance;
+
+  if ((fuzz == 0.0) && (p->red == q->red) && (p->green == q->green) &&
+      (p->blue == q->blue))
+    return(MagickTrue);
+  pixel.red=p->red-(MagickRealType) q->red;
+  distance=pixel.red*pixel.red;
+  if (distance > (fuzz*fuzz))
+    return(MagickFalse);
+  pixel.green=p->green-(MagickRealType) q->green;
+  distance+=pixel.green*pixel.green;
+  if (distance > (fuzz*fuzz))
+    return(MagickFalse);
+  pixel.blue=p->blue-(MagickRealType) q->blue;
+  distance+=pixel.blue*pixel.blue;
+  if (distance > (fuzz*fuzz))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F u z z y C o l o r C o m p a r e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FuzzyColorCompare() returns MagickTrue if the distance between two colors is
+%  less than the specified distance in a linear three dimensional color space.
+%  This method is used by ColorFloodFill() and other algorithms which
+%  compare two colors.
+%
+%  The format of the FuzzyColorCompare method is:
+%
+%      void FuzzyColorCompare(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 FuzzyColorCompare(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.2.5");
+  return(IsColorSimilar(image,p,q));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F u z z y O p a c i t y C o m p a r e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FuzzyOpacityCompare() returns true if the distance between two opacity
+%  values is less than the specified distance in a linear color space.  This
+%  method is used by MatteFloodFill() and other algorithms which compare
+%  two opacity values.
+%
+%  The format of the FuzzyOpacityCompare method is:
+%
+%      void FuzzyOpacityCompare(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 FuzzyOpacityCompare(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.2.5");
+  return(IsOpacitySimilar(image,p,q));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t C o n f i g u r e B l o b                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureBlob() returns the specified configure file as a blob.
+%
+%  The format of the GetConfigureBlob method is:
+%
+%      void *GetConfigureBlob(const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the configure file name.
+%
+%    o path: return the full path information of the configure file.
+%
+%    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 void *GetConfigureBlob(const char *filename,char *path,
+  size_t *length,ExceptionInfo *exception)
+{
+  void
+    *blob;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  assert(path != (char *) NULL);
+  assert(length != (size_t *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  blob=(void *) NULL;
+  (void) CopyMagickString(path,filename,MaxTextExtent);
+#if defined(MAGICKCORE_INSTALLED_SUPPORT)
+#if defined(MAGICKCORE_LIBRARY_PATH)
+  if (blob == (void *) NULL)
+    {
+      /*
+        Search hard coded paths.
+      */
+      (void) FormatMagickString(path,MaxTextExtent,"%s%s",
+        MAGICKCORE_LIBRARY_PATH,filename);
+      if (IsPathAccessible(path) != MagickFalse)
+        blob=FileToBlob(path,~0,length,exception);
+    }
+#endif
+#if defined(__WINDOWS__) && !(defined(MAGICKCORE_CONFIGURE_PATH) || defined(MAGICKCORE_SHARE_CONFIGURE_PATH))
+  if (blob == (void *) NULL)
+    {
+      char
+        *key_value;
+
+      /*
+        Locate file via registry key.
+      */
+      key_value=NTRegistryKeyLookup("ConfigurePath");
+      if (key_value != (char *) NULL)
+        {
+          (void) FormatMagickString(path,MaxTextExtent,"%s%s%s",key_value,
+            DirectorySeparator,filename);
+          if (IsPathAccessible(path) != MagickFalse)
+            blob=FileToBlob(path,~0,length,exception);
+        }
+    }
+#endif
+#else
+  if (blob == (void *) NULL)
+    {
+      char
+        *home;
+
+      home=GetEnvironmentValue("MAGICK_HOME");
+      if (home != (char *) NULL)
+        {
+          /*
+            Search MAGICK_HOME.
+          */
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+          (void) FormatMagickString(path,MaxTextExtent,"%s%s%s",home,
+            DirectorySeparator,filename);
+#else
+          (void) FormatMagickString(path,MaxTextExtent,"%s/lib/%s/%s",home,
+            MAGICKCORE_LIBRARY_RELATIVE_PATH,filename);
+#endif
+          if (IsPathAccessible(path) != MagickFalse)
+            blob=FileToBlob(path,~0,length,exception);
+          home=DestroyString(home);
+        }
+      home=GetEnvironmentValue("HOME");
+      if (home == (char *) NULL)
+        home=GetEnvironmentValue("USERPROFILE");
+      if (home != (char *) NULL)
+        {
+          /*
+            Search $HOME/.magick.
+          */
+          (void) FormatMagickString(path,MaxTextExtent,"%s%s.magick%s%s",home,
+            DirectorySeparator,DirectorySeparator,filename);
+          if ((IsPathAccessible(path) != MagickFalse) && (blob == (void *) NULL))
+            blob=FileToBlob(path,~0,length,exception);
+          home=DestroyString(home);
+        }
+    }
+  if ((blob == (void *) NULL) && (*GetClientPath() != '\0'))
+    {
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+      (void) FormatMagickString(path,MaxTextExtent,"%s%s%s",GetClientPath(),
+        DirectorySeparator,filename);
+#else
+      char
+        prefix[MaxTextExtent];
+
+      /*
+        Search based on executable directory if directory is known.
+      */
+      (void) CopyMagickString(prefix,GetClientPath(),
+        MaxTextExtent);
+      ChopPathComponents(prefix,1);
+      (void) FormatMagickString(path,MaxTextExtent,"%s/lib/%s/%s",prefix,
+        MAGICKCORE_LIBRARY_RELATIVE_PATH,filename);
+#endif
+      if (IsPathAccessible(path) != MagickFalse)
+        blob=FileToBlob(path,~0,length,exception);
+    }
+  /*
+    Search current directory.
+  */
+  if ((blob == (void *) NULL) && (IsPathAccessible(path) != MagickFalse))
+    blob=FileToBlob(path,~0,length,exception);
+#if defined(__WINDOWS__)
+  /*
+    Search Windows registry.
+  */
+  if (blob == (void *) NULL)
+    blob=NTResourceToBlob(filename);
+#endif
+#endif
+  if (blob == (void *) NULL)
+    (void) ThrowMagickException(exception,GetMagickModule(),ConfigureWarning,
+      "UnableToOpenConfigureFile","`%s'",path);
+  return(blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheView() 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 GetCacheView method is:
+%
+%      PixelPacket *GetCacheView(CacheView *cache_view,const long x,
+%        const long y,const unsigned long columns,const unsigned long rows)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the address of a structure of type CacheView.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+*/
+MagickExport PixelPacket *GetCacheView(CacheView *cache_view,const long x,
+  const long y,const unsigned long columns,const unsigned long rows)
+{
+  PixelPacket
+    *pixels;
+
+  pixels=GetCacheViewAuthenticPixels(cache_view,x,y,columns,rows,
+    GetCacheViewException(cache_view));
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w I n d e x e s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewIndexes() returns the indexes associated with the specified
+%  view.
+%
+%  The format of the GetCacheViewIndexes method is:
+%
+%      IndexPacket *GetCacheViewIndexes(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport IndexPacket *GetCacheViewIndexes(CacheView *cache_view)
+{
+  return(GetCacheViewAuthenticIndexQueue(cache_view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w P i x e l s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewPixels() 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 GetCacheViewPixels method is:
+%
+%      PixelPacket *GetCacheViewPixels(CacheView *cache_view,const long x,
+%        const long y,const unsigned long columns,const unsigned long rows)
+%
+%  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 PixelPacket *GetCacheViewPixels(CacheView *cache_view,const long x,
+  const long y,const unsigned long columns,const unsigned long rows)
+{
+  PixelPacket
+    *pixels;
+
+  pixels=GetCacheViewAuthenticPixels(cache_view,x,y,columns,rows,
+    GetCacheViewException(cache_view));
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e A t t r i b u t e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageAttribute() searches the list of image attributes and returns
+%  a pointer to the attribute if it exists otherwise NULL.
+%
+%  The format of the GetImageAttribute method is:
+%
+%      const ImageAttribute *GetImageAttribute(const Image *image,
+%        const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o key:  These character strings are the name of an image attribute to
+%      return.
+%
+*/
+
+static void *DestroyAttribute(void *attribute)
+{
+  register ImageAttribute
+    *p;
+
+  p=(ImageAttribute *) attribute;
+  if (p->value != (char *) NULL)
+    p->value=DestroyString(p->value);
+  return(RelinquishMagickMemory(p));
+}
+
+MagickExport const ImageAttribute *GetImageAttribute(const Image *image,
+  const char *key)
+{
+  const char
+    *value;
+
+  ImageAttribute
+    *attribute;
+
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.3.1");
+  value=GetImageProperty(image,key);
+  if (value == (const char *) NULL)
+    return((const ImageAttribute *) NULL);
+  if (image->attributes == (void *) NULL)
+    ((Image *) image)->attributes=NewSplayTree(CompareSplayTreeString,
+      RelinquishMagickMemory,DestroyAttribute);
+  else
+    {
+      const ImageAttribute
+        *attribute;
+
+      attribute=(const ImageAttribute *) GetValueFromSplayTree((SplayTreeInfo *)
+        image->attributes,key);
+      if (attribute != (const ImageAttribute *) NULL)
+        return(attribute);
+    }
+  attribute=(ImageAttribute *) AcquireMagickMemory(sizeof(*attribute));
+  if (attribute == (ImageAttribute *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(attribute,0,sizeof(*attribute));
+  attribute->key=ConstantString(key);
+  attribute->value=ConstantString(value);
+  (void) AddValueToSplayTree((SplayTreeInfo *) ((Image *) image)->attributes,
+    attribute->key,attribute);
+  return((const ImageAttribute *) attribute);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C l i p p i n g P a t h A t t r i b u t e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageClippingPathAttribute() searches the list of image attributes and
+%  returns a pointer to a clipping path if it exists otherwise NULL.
+%
+%  The format of the GetImageClippingPathAttribute method is:
+%
+%      const ImageAttribute *GetImageClippingPathAttribute(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o attribute:  Method GetImageClippingPathAttribute returns the clipping
+%      path if it exists otherwise NULL.
+%
+%    o image: the image.
+%
+*/
+MagickExport const ImageAttribute *GetImageClippingPathAttribute(Image *image)
+{
+  return(GetImageAttribute(image,"8BIM:1999,2998"));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e F r o m M a g i c k R e g i s t r y                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageFromMagickRegistry() gets an image from the registry as defined by
+%  its name.  If the image is not found, a NULL image is returned.
+%
+%  The format of the GetImageFromMagickRegistry method is:
+%
+%      Image *GetImageFromMagickRegistry(const char *name,long *id,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the name of the image to retrieve from the registry.
+%
+%    o id: the registry id.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *GetImageFromMagickRegistry(const char *name,long *id,
+  ExceptionInfo *exception)
+{
+  *id=0L;
+  return((Image *) GetImageRegistry(ImageRegistryType,name,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k R e g i s t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickRegistry() gets a blob from the registry as defined by the id.  If
+%  the blob that matches the id is not found, NULL is returned.
+%
+%  The format of the GetMagickRegistry method is:
+%
+%      const void *GetMagickRegistry(const long id,RegistryType *type,
+%        size_t *length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o id: the registry id.
+%
+%    o type: the registry type.
+%
+%    o length: the blob length in number of bytes.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void *GetMagickRegistry(const long id,RegistryType *type,
+  size_t *length,ExceptionInfo *exception)
+{
+  char
+    key[MaxTextExtent];
+
+  void
+    *blob;
+
+  *type=UndefinedRegistryType;
+  *length=0;
+  (void) FormatMagickString(key,MaxTextExtent,"%ld\n",id);
+  blob=(void *) GetImageRegistry(ImageRegistryType,key,exception);
+  if (blob != (void *) NULL)
+    return(blob);
+  blob=(void *) GetImageRegistry(ImageInfoRegistryType,key,exception);
+  if (blob != (void *) NULL)
+    return(blob);
+  return((void *) GetImageRegistry(UndefinedRegistryType,key,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e G e o m e t r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageGeometry() returns a region as defined by the geometry string with
+%  respect to the image and its gravity.
+%
+%  The format of the GetImageGeometry method is:
+%
+%      int GetImageGeometry(Image *image,const char *geometry,
+%        const unsigned int size_to_fit,RectangeInfo *region_info)
+%
+%  A description of each parameter follows:
+%
+%    o flags:  Method GetImageGeometry returns a bitmask that indicates
+%      which of the four values were located in the geometry string.
+%
+%    o geometry:  The geometry (e.g. 100x100+10+10).
+%
+%    o size_to_fit:  A value other than 0 means to scale the region so it
+%      fits within the specified width and height.
+%
+%    o region_info: the region as defined by the geometry string with
+%      respect to the image and its gravity.
+%
+*/
+MagickExport int GetImageGeometry(Image *image,const char *geometry,
+  const unsigned int size_to_fit,RectangleInfo *region_info)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.4");
+  if (size_to_fit != MagickFalse)
+    return((int) ParseRegionGeometry(image,geometry,region_info,&image->exception));
+  return((int) ParsePageGeometry(image,geometry,region_info,&image->exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageList() returns an image at the specified position in the list.
+%
+%  The format of the GetImageList method is:
+%
+%      Image *GetImageList(const Image *images,const long offset,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o offset: the position within the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *GetImageList(const Image *images,const long offset,
+  ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  image=CloneImage(GetImageFromList(images,(long) offset),0,0,MagickTrue,
+    exception);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e L i s t I n d e x                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageListIndex() returns the position in the list of the specified
+%  image.
+%
+%  The format of the GetImageListIndex method is:
+%
+%      long GetImageListIndex(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport long GetImageListIndex(const Image *images)
+{
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(GetImageIndexInList(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e L i s t S i z e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageListSize() returns the number of images in the list.
+%
+%  The format of the GetImageListSize method is:
+%
+%      unsigned long GetImageListSize(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport unsigned long GetImageListSize(const Image *images)
+{
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(GetImageListLength(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e P i x e l s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImagePixels() obtains a pixel region for read/write access. If the
+%  region is successfully accessed, a pointer to a PixelPacket 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 RAM, or in a memory-mapped file. The returned pointer
+%  should *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket. If the image type is CMYK or if the storage class is
+%  PseduoClass, call GetAuthenticIndexQueue() after invoking GetImagePixels()
+%  to obtain the black color component or colormap indexes (of type IndexPacket)
+%  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
+%  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 GetImagePixels() method is:
+%
+%      PixelPacket *GetImagePixels(Image *image,const long x,const long y,
+%        const unsigned long columns,const unsigned long rows)
+%
+%  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.
+%
+*/
+MagickExport PixelPacket *GetImagePixels(Image *image,const long x,const long y,
+  const unsigned long columns,const unsigned long rows)
+{
+  return(GetAuthenticPixels(image,x,y,columns,rows,&image->exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I n d e x e s                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetIndexes() returns the black channel or the colormap indexes associated
+%  with the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
+%  returned if the black channel or colormap indexes are not available.
+%
+%  The format of the GetIndexes() method is:
+%
+%      IndexPacket *GetIndexes(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o indexes: GetIndexes() returns the indexes associated with the last
+%      call to QueueAuthenticPixels() or GetAuthenticPixels().
+%
+%    o image: the image.
+%
+*/
+MagickExport IndexPacket *GetIndexes(const Image *image)
+{
+  return(GetAuthenticIndexQueue(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k G e o m e t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickGeometry() is similar to GetGeometry() except the returned
+%  geometry is modified as determined by the meta characters:  %, !, <, >,
+%  and ~.
+%
+%  The format of the GetMagickGeometry method is:
+%
+%      unsigned int GetMagickGeometry(const char *geometry,long *x,long *y,
+%        unsigned long *width,unsigned long *height)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  Specifies a character string representing the geometry
+%      specification.
+%
+%    o x,y:  A pointer to an integer.  The x and y offset as determined by
+%      the geometry specification is returned here.
+%
+%    o width,height:  A pointer to an unsigned integer.  The width and height
+%      as determined by the geometry specification is returned here.
+%
+*/
+MagickExport unsigned int GetMagickGeometry(const char *geometry,long *x,
+  long *y,unsigned long *width,unsigned long *height)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.3");
+  return(ParseMetaGeometry(geometry,x,y,width,height));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImage() returns the next image in a list.
+%
+%  The format of the GetNextImage method is:
+%
+%      Image *GetNextImage(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetNextImage(const Image *images)
+{
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(GetNextImageInList(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e A t t r i b u t e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageAttribute() gets the next image attribute.
+%
+%  The format of the GetNextImageAttribute method is:
+%
+%      const ImageAttribute *GetNextImageAttribute(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const ImageAttribute *GetNextImageAttribute(const Image *image)
+{
+  const char
+    *property;
+
+  property=GetNextImageProperty(image);
+  if (property == (const char *) NULL)
+    return((const ImageAttribute *) NULL);
+  return(GetImageAttribute(image,property));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N u m b e r S c e n e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNumberScenes() returns the number of images in the list.
+%
+%  The format of the GetNumberScenes method is:
+%
+%      unsigned int GetNumberScenes(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport unsigned int GetNumberScenes(const Image *image)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return((unsigned int) GetImageListLength(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e P i x e l                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOnePixel() returns a single pixel at the specified (x,y) location.
+%  The image background color is returned if an error occurs.
+%
+%  The format of the GetOnePixel() method is:
+%
+%      PixelPacket GetOnePixel(const Image image,const long x,const long y)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+*/
+MagickExport PixelPacket GetOnePixel(Image *image,const long x,const long y)
+{
+  PixelPacket
+    pixel;
+
+  (void) GetOneAuthenticPixel(image,x,y,&pixel,&image->exception);
+  return(pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P i x e l s                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixels() returns the pixels associated with the last call to
+%  QueueAuthenticPixels() or GetAuthenticPixels().
+%
+%  The format of the GetPixels() method is:
+%
+%      PixelPacket *GetPixels(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o pixels: GetPixels() returns the pixels associated with the last call
+%      to QueueAuthenticPixels() or GetAuthenticPixels().
+%
+%    o image: the image.
+%
+*/
+MagickExport PixelPacket *GetPixels(const Image *image)
+{
+  return(GetAuthenticPixelQueue(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P r e v i o u s I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPreviousImage() returns the previous image in a list.
+%
+%  The format of the GetPreviousImage method is:
+%
+%      Image *GetPreviousImage(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetPreviousImage(const Image *images)
+{
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(GetPreviousImageInList(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H S L T r a n s f o r m                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HSLTransform() converts a (hue, saturation, lightness) to a (red, green,
+%  blue) triple.
+%
+%  The format of the HSLTransformImage method is:
+%
+%      void HSLTransform(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 HueToRGB(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 HSLTransform(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 (lightness <= 0.5)
+    m2=lightness*(saturation+1.0);
+  else
+    m2=lightness+saturation-lightness*saturation;
+  m1=2.0*lightness-m2;
+  r=HueToRGB(m1,m2,hue+1.0/3.0);
+  g=HueToRGB(m1,m2,hue);
+  b=HueToRGB(m1,m2,hue-1.0/3.0);
+  *red=RoundToQuantum((MagickRealType) QuantumRange*r);
+  *green=RoundToQuantum((MagickRealType) QuantumRange*g);
+  *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I d e n t i t y A f f i n e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IdentityAffine() initializes the affine transform to the identity matrix.
+%
+%  The format of the IdentityAffine method is:
+%
+%      IdentityAffine(AffineMatrix *affine)
+%
+%  A description of each parameter follows:
+%
+%    o affine: A pointer the affine transform of type AffineMatrix.
+%
+*/
+MagickExport void IdentityAffine(AffineMatrix *affine)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  assert(affine != (AffineMatrix *) NULL);
+  (void) ResetMagickMemory(affine,0,sizeof(AffineMatrix));
+  affine->sx=1.0;
+  affine->sy=1.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n i t i a l i z e M a g i c k                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeMagick() initializes the ImageMagick environment.
+%
+%  The format of the InitializeMagick function is:
+%
+%      InitializeMagick(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: the execution path of the current ImageMagick client.
+%
+*/
+MagickExport void InitializeMagick(const char *path)
+{
+  MagickCoreGenesis(path,MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e P i x e l C o l o r                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolatePixelColor() applies bi-linear or tri-linear interpolation
+%  between a pixel and it's neighbors.
+%
+%  The format of the InterpolatePixelColor method is:
+%
+%      MagickPixelPacket InterpolatePixelColor(const Image *image,
+%        CacheView *view_info,InterpolatePixelMethod method,const double x,
+%        const double y,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o image_view: the image cache view.
+%
+%    o type:  the type of pixel color interpolation.
+%
+%    o x,y: A double representing the current (x,y) position of the pixel.
+%
+%    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 void BicubicInterpolate(const MagickPixelPacket *pixels,const double dx,
+  MagickPixelPacket *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].opacity-pixels[2].opacity)-(pixels[0].opacity-pixels[1].opacity);
+  q=(pixels[0].opacity-pixels[1].opacity)-p;
+  r=pixels[2].opacity-pixels[0].opacity;
+  s=pixels[1].opacity;
+  pixel->opacity=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  if (pixel->colorspace == CMYKColorspace)
+    {
+      p=(pixels[3].index-pixels[2].index)-(pixels[0].index-pixels[1].index);
+      q=(pixels[0].index-pixels[1].index)-p;
+      r=pixels[2].index-pixels[0].index;
+      s=pixels[1].index;
+      pixel->index=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+    }
+}
+
+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 long NearestNeighbor(MagickRealType x)
+{
+  if (x >= 0.0)
+    return((long) (x+0.5));
+  return((long) (x-0.5));
+}
+
+MagickExport MagickPixelPacket InterpolatePixelColor(const Image *image,
+  CacheView *image_view,const InterpolatePixelMethod method,const double x,
+  const double y,ExceptionInfo *exception)
+{
+  MagickPixelPacket
+    pixel;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image_view != (CacheView *) NULL);
+  GetMagickPixelPacket(image,&pixel);
+  switch (method)
+  {
+    case AverageInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[16];
+
+      MagickRealType
+        alpha[16],
+        gamma;
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x)-1,(long) floor(y)-1,
+        4,4,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      for (i=0; i < 16L; i++)
+      {
+        GetMagickPixelPacket(image,pixels+i);
+        SetMagickPixelPacket(image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        gamma=alpha[i];
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        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.opacity+=0.0625*pixels[i].opacity;
+        if (image->colorspace == CMYKColorspace)
+          pixel.index+=gamma*0.0625*pixels[i].index;
+        p++;
+      }
+      break;
+    }
+    case BicubicInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[16],
+        u[4];
+
+      MagickRealType
+        alpha[16];
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x)-1,(long) floor(y)-1,
+        4,4,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      for (i=0; i < 16L; i++)
+      {
+        GetMagickPixelPacket(image,pixels+i);
+        SetMagickPixelPacket(image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        p++;
+      }
+      delta.x=x-floor(x);
+      for (i=0; i < 4L; i++)
+        BicubicInterpolate(pixels+4*i,delta.x,u+i);
+      delta.y=y-floor(y);
+      BicubicInterpolate(u,delta.y,&pixel);
+      break;
+    }
+    case BilinearInterpolatePixel:
+    default:
+    {
+      MagickPixelPacket
+        pixels[16];
+
+      MagickRealType
+        alpha[16],
+        gamma;
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x),(long) floor(y),2,2,
+        exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      for (i=0; i < 4L; i++)
+      {
+        GetMagickPixelPacket(image,pixels+i);
+        SetMagickPixelPacket(image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        p++;
+      }
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      gamma=(((1.0-delta.y)*((1.0-delta.x)*alpha[0]+delta.x*alpha[1])+delta.y*
+        ((1.0-delta.x)*alpha[2]+delta.x*alpha[3])));
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      pixel.red=gamma*((1.0-delta.y)*((1.0-delta.x)*pixels[0].red+delta.x*
+        pixels[1].red)+delta.y*((1.0-delta.x)*pixels[2].red+delta.x*
+        pixels[3].red));
+      pixel.green=gamma*((1.0-delta.y)*((1.0-delta.x)*pixels[0].green+delta.x*
+        pixels[1].green)+delta.y*((1.0-delta.x)*pixels[2].green+
+        delta.x*pixels[3].green));
+      pixel.blue=gamma*((1.0-delta.y)*((1.0-delta.x)*pixels[0].blue+delta.x*
+        pixels[1].blue)+delta.y*((1.0-delta.x)*pixels[2].blue+delta.x*
+        pixels[3].blue));
+      pixel.opacity=((1.0-delta.y)*((1.0-delta.x)*pixels[0].opacity+delta.x*
+        pixels[1].opacity)+delta.y*((1.0-delta.x)*pixels[2].opacity+delta.x*
+        pixels[3].opacity));
+      if (image->colorspace == CMYKColorspace)
+        pixel.index=gamma*((1.0-delta.y)*((1.0-delta.x)*pixels[0].index+delta.x*
+          pixels[1].index)+delta.y*((1.0-delta.x)*pixels[2].index+delta.x*
+          pixels[3].index));
+      break;
+    }
+    case FilterInterpolatePixel:
+    {
+      Image
+        *excerpt_image,
+        *filter_image;
+
+      MagickPixelPacket
+        pixels[1];
+
+      RectangleInfo
+        geometry;
+
+      geometry.width=4L;
+      geometry.height=4L;
+      geometry.x=(long) floor(x)-1L;
+      geometry.y=(long) floor(y)-1L;
+      excerpt_image=ExcerptImage(image,&geometry,exception);
+      if (excerpt_image == (Image *) NULL)
+        break;
+      filter_image=ResizeImage(excerpt_image,1,1,image->filter,image->blur,
+        exception);
+      excerpt_image=DestroyImage(excerpt_image);
+      if (filter_image == (Image *) NULL)
+        break;
+      p=GetVirtualPixels(filter_image,0,0,1,1,exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          filter_image=DestroyImage(filter_image);
+          break;
+        }
+      indexes=GetVirtualIndexQueue(filter_image);
+      GetMagickPixelPacket(image,pixels);
+      SetMagickPixelPacket(image,p,indexes,&pixel);
+      filter_image=DestroyImage(filter_image);
+      break;
+    }
+    case IntegerInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[1];
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x),(long) floor(y),1,1,
+        exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      GetMagickPixelPacket(image,pixels);
+      SetMagickPixelPacket(image,p,indexes,&pixel);
+      break;
+    }
+    case MeshInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[4];
+
+      MagickRealType
+        alpha[4],
+        gamma;
+
+      PointInfo
+        delta,
+        luminance;
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x),(long) floor(y),
+        2,2,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      for (i=0; i < 4L; i++)
+      {
+        GetMagickPixelPacket(image,pixels+i);
+        SetMagickPixelPacket(image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        p++;
+      }
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      luminance.x=MagickPixelLuminance(pixels+0)-MagickPixelLuminance(pixels+3);
+      luminance.y=MagickPixelLuminance(pixels+1)-MagickPixelLuminance(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.opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
+                pixels[3].opacity,pixels[0].opacity);
+              if (image->colorspace == CMYKColorspace)
+                pixel.index=gamma*MeshInterpolate(&delta,pixels[2].index,
+                  pixels[3].index,pixels[0].index);
+            }
+          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.opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
+                pixels[0].opacity,pixels[3].opacity);
+              if (image->colorspace == CMYKColorspace)
+                pixel.index=gamma*MeshInterpolate(&delta,pixels[1].index,
+                  pixels[0].index,pixels[3].index);
+            }
+        }
+      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.opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
+                pixels[1].opacity,pixels[2].opacity);
+              if (image->colorspace == CMYKColorspace)
+                pixel.index=gamma*MeshInterpolate(&delta,pixels[0].index,
+                  pixels[1].index,pixels[2].index);
+            }
+          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.opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
+                pixels[2].opacity,pixels[1].opacity);
+              if (image->colorspace == CMYKColorspace)
+                pixel.index=gamma*MeshInterpolate(&delta,pixels[3].index,
+                  pixels[2].index,pixels[1].index);
+            }
+        }
+      break;
+    }
+    case NearestNeighborInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[1];
+
+      p=GetCacheViewVirtualPixels(image_view,NearestNeighbor(x),NearestNeighbor(y),
+        1,1,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      GetMagickPixelPacket(image,pixels);
+      SetMagickPixelPacket(image,p,indexes,&pixel);
+      break;
+    }
+    case SplineInterpolatePixel:
+    {
+      long
+        j,
+        n;
+
+      MagickPixelPacket
+        pixels[16];
+
+      MagickRealType
+        alpha[16],
+        dx,
+        dy,
+        gamma;
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(image_view,(long) floor(x)-1,(long) floor(y)-1,
+        4,4,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      n=0;
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      for (i=(-1); i < 3L; i++)
+      {
+        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
+        for (j=(-1); j < 3L; j++)
+        {
+          GetMagickPixelPacket(image,pixels+n);
+          SetMagickPixelPacket(image,p,indexes+n,pixels+n);
+          alpha[n]=1.0;
+          if (image->matte != MagickFalse)
+            {
+              alpha[n]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+              pixels[n].red*=alpha[n];
+              pixels[n].green*=alpha[n];
+              pixels[n].blue*=alpha[n];
+              if (image->colorspace == CMYKColorspace)
+                pixels[n].index*=alpha[n];
+            }
+          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
+          gamma=alpha[n];
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          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->matte != MagickFalse)
+            pixel.opacity+=dx*dy*pixels[n].opacity;
+          if (image->colorspace == CMYKColorspace)
+            pixel.index+=gamma*dx*dy*pixels[n].index;
+          n++;
+          p++;
+        }
+      }
+      break;
+    }
+  }
+  return(pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p r e t I m a g e A t t r i b u t e s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpretImageAttributes() replaces any embedded formatting characters with
+%  the appropriate image attribute and returns the translated text.
+%
+%  The format of the InterpretImageAttributes method is:
+%
+%      char *InterpretImageAttributes(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 *InterpretImageAttributes(const ImageInfo *image_info,
+  Image *image,const char *embed_text)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.3.1");
+  return(InterpretImageProperties(image_info,image,embed_text));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     I s S u b i m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsSubimage() returns MagickTrue if the geometry is a valid subimage
+%  specification (e.g. [1], [1-9], [1,7,4]).
+%
+%  The format of the IsSubimage method is:
+%
+%      unsigned int IsSubimage(const char *geometry,const unsigned int 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 unsigned int IsSubimage(const char *geometry,
+  const unsigned int pedantic)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (geometry == (const char *) NULL)
+    return(MagickFalse);
+  if ((strchr(geometry,'x') != (char *) NULL) ||
+      (strchr(geometry,'X') != (char *) NULL))
+    return(MagickFalse);
+  if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i b e r a t e M e m o r y                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LiberateMemory() frees memory that has already been allocated, and NULL's
+%  the pointer to it.
+%
+%  The format of the LiberateMemory method is:
+%
+%      void LiberateMemory(void **memory)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a block of memory to free for reuse.
+%
+*/
+MagickExport void LiberateMemory(void **memory)
+{
+  assert(memory != (void **) NULL);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (*memory == (void *) NULL)
+    return;
+  free(*memory);
+  *memory=(void *) NULL;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i b e r a t e S e m a p h o r e I n f o                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LiberateSemaphoreInfo() relinquishes a semaphore.
+%
+%  The format of the LiberateSemaphoreInfo method is:
+%
+%      LiberateSemaphoreInfo(void **semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void LiberateSemaphoreInfo(SemaphoreInfo **semaphore_info)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  RelinquishSemaphoreInfo(*semaphore_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k I n c a r n a t e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickIncarnate() initializes the ImageMagick environment.
+%
+%  The format of the MagickIncarnate function is:
+%
+%      MagickIncarnate(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: the execution path of the current ImageMagick client.
+%
+*/
+
+MagickExport void MagickIncarnate(const char *path)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.1");
+  InitializeMagick(path);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k M o n i t o r                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickMonitor() calls the monitor handler method with a text string that
+%  describes the task and a measure of completion.  The method returns
+%  MagickTrue on success otherwise MagickFalse if an error is encountered, e.g.
+%  if there was a user interrupt.
+%
+%  The format of the MagickMonitor method is:
+%
+%      MagickBooleanType MagickMonitor(const char *text,
+%        const MagickOffsetType offset,const MagickSizeType span,
+%        void *client_data)
+%
+%  A description of each parameter follows:
+%
+%    o offset: the position relative to the span parameter which represents
+%      how much progress has been made toward completing a task.
+%
+%    o span: the span relative to completing a task.
+%
+%    o client_data: the client data.
+%
+*/
+MagickExport MagickBooleanType MagickMonitor(const char *text,
+  const MagickOffsetType offset,const MagickSizeType span,
+  void *magick_unused(client_data))
+{
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  assert(text != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",text);
+  ProcessPendingEvents(text);
+  status=MagickTrue;
+  exception=AcquireExceptionInfo();
+  if (monitor_handler != (MonitorHandler) NULL)
+    status=(*monitor_handler)(text,offset,span,exception);
+  exception=DestroyExceptionInfo(exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a p I m a g e                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MapImage() replaces the colors of an image with the closest color from a
+%  reference image.
+%
+%  The format of the MapImage method is:
+%
+%      MagickBooleanType MapImage(Image *image,const Image *map_image,
+%        const MagickBooleanType dither)
+%
+%  A description of each parameter follows:
+%
+%    o image: Specifies a pointer to an Image structure.
+%
+%    o map_image: the image.  Reduce image to a set of colors represented by
+%      this image.
+%
+%    o dither: Set this integer value to something other than zero to
+%      dither the mapped image.
+%
+*/
+MagickExport MagickBooleanType MapImage(Image *image,const Image *map_image,
+  const MagickBooleanType dither)
+{
+  QuantizeInfo
+    quantize_info;
+
+  /*
+    Initialize color cube.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(map_image != (Image *) NULL);
+  assert(map_image->signature == MagickSignature);
+  GetQuantizeInfo(&quantize_info);
+  quantize_info.dither=dither;
+  return(RemapImage(&quantize_info,image,map_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a p I m a g e s                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MapImages() replaces the colors of a sequence of images with the closest
+%  color from a reference image.
+%
+%  The format of the MapImage method is:
+%
+%      MagickBooleanType MapImages(Image *images,Image *map_image,
+%        const MagickBooleanType dither)
+%
+%  A description of each parameter follows:
+%
+%    o image: Specifies a pointer to a set of Image structures.
+%
+%    o map_image: the image.  Reduce image to a set of colors represented by
+%      this image.
+%
+%    o dither: Set this integer value to something other than zero to
+%      dither the quantized image.
+%
+*/
+MagickExport MagickBooleanType MapImages(Image *images,const Image *map_image,
+  const MagickBooleanType dither)
+{
+  QuantizeInfo
+    quantize_info;
+
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  GetQuantizeInfo(&quantize_info);
+  quantize_info.dither=dither;
+  return(RemapImages(&quantize_info,images,map_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a t t e F l o o d f i l l I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MatteFloodfill() changes the transparency value of any pixel that matches
+%  target and is an immediate neighbor.  If the method FillToBorderMethod
+%  is specified, the transparency value is changed for any neighbor pixel
+%  that does not match the bordercolor member of image.
+%
+%  By default target must match a particular pixel transparency exactly.
+%  However, in many cases two transparency values may differ by a
+%  small amount.  The fuzz member of image defines how much tolerance is
+%  acceptable to consider two transparency values as the same.  For example,
+%  set fuzz to 10 and the opacity values of 100 and 102 respectively are
+%  now interpreted as the same value for the purposes of the floodfill.
+%
+%  The format of the MatteFloodfillImage method is:
+%
+%      MagickBooleanType MatteFloodfillImage(Image *image,
+%        const PixelPacket target,const Quantum opacity,const long x_offset,
+%        const long y_offset,const PaintMethod method)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target: the RGB value of the target color.
+%
+%    o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
+%      fully transparent.
+%
+%    o x,y: the starting location of the operation.
+%
+%    o method:  Choose either FloodfillMethod or FillToBorderMethod.
+%
+*/
+MagickExport MagickBooleanType MatteFloodfillImage(Image *image,
+  const PixelPacket target,const Quantum opacity,const long x_offset,
+  const long y_offset,const PaintMethod method)
+{
+  Image
+    *floodplane_image;
+
+  long
+    offset,
+    start,
+    x,
+    x1,
+    x2,
+    y;
+
+  MagickBooleanType
+    skip;
+
+  register SegmentInfo
+    *s;
+
+  SegmentInfo
+    *segment_stack;
+
+  /*
+    Check boundary conditions.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((x_offset < 0) || (x_offset >= (long) image->columns))
+    return(MagickFalse);
+  if ((y_offset < 0) || (y_offset >= (long) image->rows))
+    return(MagickFalse);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    &image->exception);
+  if (floodplane_image == (Image *) NULL)
+    return(MagickFalse);
+  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
+  /*
+    Set floodfill color.
+  */
+  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.
+  */
+  x=x_offset;
+  y=y_offset;
+  start=0;
+  s=segment_stack;
+  PushSegmentStack(y,x,x,1);
+  PushSegmentStack(y+1,x,x,-1);
+  while (s > segment_stack)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Pop segment off stack.
+    */
+    s--;
+    x1=(long) s->x1;
+    x2=(long) s->x2;
+    offset=(long) s->y2;
+    y=(long) s->y1+offset;
+    /*
+      Recolor neighboring pixels.
+    */
+    p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,&image->exception);
+    q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1,
+      &image->exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    p+=x1;
+    q+=x1;
+    for (x=x1; x >= 0; x--)
+    {
+      if (q->opacity == (Quantum) TransparentOpacity)
+        break;
+      if (method == FloodfillMethod)
+        {
+          if (IsColorSimilar(image,p,&target) == MagickFalse)
+            break;
+        }
+      else
+        if (IsColorSimilar(image,p,&target) != MagickFalse)
+          break;
+      q->opacity=(Quantum) TransparentOpacity;
+      q--;
+      p--;
+    }
+    if (SyncAuthenticPixels(floodplane_image,&image->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 < (long) image->columns)
+            {
+              p=GetVirtualPixels(image,x,y,image->columns-x,1,
+                &image->exception);
+              q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1,
+                &image->exception);
+              if ((p == (const PixelPacket *) NULL) ||
+                  (q == (PixelPacket *) NULL))
+                break;
+              for ( ; x < (long) image->columns; x++)
+              {
+                if (q->opacity == (Quantum) TransparentOpacity)
+                  break;
+                if (method == FloodfillMethod)
+                  {
+                    if (IsColorSimilar(image,p,&target) == MagickFalse)
+                      break;
+                  }
+                else
+                  if (IsColorSimilar(image,p,&target) != MagickFalse)
+                    break;
+                q->opacity=(Quantum) TransparentOpacity;
+                q++;
+                p++;
+              }
+              if (SyncAuthenticPixels(floodplane_image,&image->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=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,
+            &image->exception);
+          q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1,
+            &image->exception);
+          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+            break;
+          for ( ; x <= x2; x++)
+          {
+            if (q->opacity == (Quantum) TransparentOpacity)
+              break;
+            if (method == FloodfillMethod)
+              {
+                if (IsColorSimilar(image,p,&target) != MagickFalse)
+                  break;
+              }
+            else
+              if (IsColorSimilar(image,p,&target) == MagickFalse)
+                break;
+            p++;
+            q++;
+          }
+        }
+      start=x;
+    } while (x <= x2);
+  }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Tile fill color onto floodplane.
+    */
+    p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,
+      &image->exception);
+    q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (p->opacity != OpaqueOpacity)
+        q->opacity=opacity;
+      p++;
+      q++;
+    }
+    if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+      break;
+  }
+  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
+  floodplane_image=DestroyImage(floodplane_image);
+  return(y == (long) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o s a i c I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MosaicImages() Obsolete Function: Use MergeImageLayers() instead.
+%
+%  The format of the MosaicImage method is:
+%
+%      Image *MosaicImages(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image list to be composited together
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *MosaicImages(Image *image,ExceptionInfo *exception)
+{
+  return(MergeImageLayers(image,MosaicLayer,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O p a q u e I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpaqueImage() 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 OpaqueImage method is:
+%
+%      MagickBooleanType OpaqueImage(Image *image,
+%        const PixelPacket *target,const PixelPacket fill)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target: the RGB value of the target color.
+%
+%    o fill: the replacement color.
+%
+*/
+MagickExport MagickBooleanType OpaqueImage(Image *image,
+  const PixelPacket target,const PixelPacket fill)
+{
+#define OpaqueImageTag  "Opaque/Image"
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  register long
+    i;
+
+  /*
+    Make image color opaque.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.1.0");
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  switch (image->storage_class)
+  {
+    case DirectClass:
+    default:
+    {
+      /*
+        Make DirectClass image opaque.
+      */
+      for (y=0; y < (long) image->rows; y++)
+      {
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          if (IsColorSimilar(image,q,&target) != MagickFalse)
+            *q=fill;
+          q++;
+        }
+        if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+          break;
+        proceed=SetImageProgress(image,OpaqueImageTag,y,image->rows);
+        if (proceed == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case PseudoClass:
+    {
+      /*
+        Make PseudoClass image opaque.
+      */
+      for (i=0; i < (long) image->colors; i++)
+      {
+        if (IsColorSimilar(image,&image->colormap[i],&target) != MagickFalse)
+          image->colormap[i]=fill;
+      }
+      if (fill.opacity != OpaqueOpacity)
+        {
+          for (y=0; y < (long) image->rows; y++)
+          {
+            register long
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              if (IsColorSimilar(image,q,&target) != MagickFalse)
+                q->opacity=fill.opacity;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+              break;
+          }
+        }
+      (void) SyncImage(image);
+      break;
+    }
+  }
+  if (fill.opacity != OpaqueOpacity)
+    image->matte=MagickTrue;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   O p e n C a c h e V i e w                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenCacheView() opens a view into the pixel cache, using the
+%  VirtualPixelMethod that is defined within the given image itself.
+%
+%  The format of the OpenCacheView method is:
+%
+%      CacheView *OpenCacheView(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport CacheView *OpenCacheView(const Image *image)
+{
+  return(AcquireCacheView(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a i n t F l o o d f i l l I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PaintFloodfill() 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 PaintFloodfillImage method is:
+%
+%      MagickBooleanType PaintFloodfillImage(Image *image,
+%        const ChannelType channel,const MagickPixelPacket target,const long x,
+%        const long y,const DrawInfo *draw_info,const PaintMethod method)
+%
+%  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 x,y: the starting location of the operation.
+%
+%    o draw_info: the draw info.
+%
+%    o method: Choose either FloodfillMethod or FillToBorderMethod.
+%
+*/
+MagickExport MagickBooleanType PaintFloodfillImage(Image *image,
+  const ChannelType channel,const MagickPixelPacket *target,const long x,
+  const long y,const DrawInfo *draw_info,const PaintMethod method)
+{
+  MagickBooleanType
+    status;
+
+  status=FloodfillPaintImage(image,channel,draw_info,target,x,y,
+    method == FloodfillMethod ? MagickFalse : MagickTrue);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%     P a i n t O p a q u e I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PaintOpaqueImage() 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 PaintOpaqueImage method is:
+%
+%      MagickBooleanType PaintOpaqueImage(Image *image,
+%        const PixelPacket *target,const PixelPacket *fill)
+%      MagickBooleanType PaintOpaqueImageChannel(Image *image,
+%        const ChannelType channel,const PixelPacket *target,
+%        const PixelPacket *fill)
+%
+%  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.
+%
+*/
+
+MagickExport MagickBooleanType PaintOpaqueImage(Image *image,
+  const MagickPixelPacket *target,const MagickPixelPacket *fill)
+{
+  return(PaintOpaqueImageChannel(image,DefaultChannels,target,fill));
+}
+
+MagickExport MagickBooleanType PaintOpaqueImageChannel(Image *image,
+  const ChannelType channel,const MagickPixelPacket *target,
+  const MagickPixelPacket *fill)
+{
+  return(OpaquePaintImageChannel(image,channel,target,fill,MagickFalse));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P a i n t T r a n s p a r e n t I m a g e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PaintTransparentImage() 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 PaintTransparentImage method is:
+%
+%      MagickBooleanType PaintTransparentImage(Image *image,
+%        const MagickPixelPacket *target,const Quantum opacity)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target: the RGB value of the target color.
+%
+%    o opacity: the replacement opacity value.
+%
+*/
+MagickExport MagickBooleanType PaintTransparentImage(Image *image,
+  const MagickPixelPacket *target,const Quantum opacity)
+{
+  return(TransparentPaintImage(image,target,opacity,MagickFalse));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P a r s e I m a g e G e o m e t r y                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseImageGeometry() is similar to GetGeometry() except the returned
+%  geometry is modified as determined by the meta characters:  %, !, <,
+%  and >.
+%
+%  The format of the ParseImageGeometry method is:
+%
+%      int ParseImageGeometry(char *geometry,long *x,long *y,
+%        unsigned long *width,unsigned long *height)
+%
+%  A description of each parameter follows:
+%
+%    o flags:  Method ParseImageGeometry returns a bitmask that indicates
+%      which of the four values were located in the geometry string.
+%
+%    o image_geometry:  Specifies a character string representing the geometry
+%      specification.
+%
+%    o x,y:  A pointer to an integer.  The x and y offset as determined by
+%      the geometry specification is returned here.
+%
+%    o width,height:  A pointer to an unsigned integer.  The width and height
+%      as determined by the geometry specification is returned here.
+%
+*/
+MagickExport int ParseImageGeometry(const char *geometry,long *x,long *y,
+  unsigned long *width,unsigned long *height)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.1");
+  return((int) ParseMetaGeometry(geometry,x,y,width,height));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e S i z e G e o m e t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseSizeGeometry() returns a region as defined by the geometry string with
+%  respect to the image dimensions and aspect ratio.
+%
+%  The format of the ParseSizeGeometry method is:
+%
+%      MagickStatusType ParseSizeGeometry(const Image *image,
+%        const char *geometry,RectangeInfo *region_info)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry (e.g. 100x100+10+10).
+%
+%    o region_info: the region as defined by the geometry string.
+%
+*/
+MagickExport MagickStatusType ParseSizeGeometry(const Image *image,
+  const char *geometry,RectangleInfo *region_info)
+{
+  MagickStatusType
+    flags;
+
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.4.7");
+  SetGeometry(image,region_info);
+  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
+    &region_info->width,&region_info->height);
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P o p I m a g e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PopImageList() removes the last image in the list.
+%
+%  The format of the PopImageList method is:
+%
+%      Image *PopImageList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *PopImageList(Image **images)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(RemoveLastImageFromList(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P o p I m a g e P i x e l s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PopImagePixels() 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 PopImagePixels method is:
+%
+%      size_t PopImagePixels(Image *,const QuantumType quantum,
+%        unsigned char *destination)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum: Declare which pixel components to transfer (RGB, RGBA, etc).
+%
+%    o destination:  The components are transferred to this buffer.
+%
+*/
+MagickExport size_t PopImagePixels(Image *image,const QuantumType quantum,
+  unsigned char *destination)
+{
+  QuantumInfo
+    *quantum_info;
+
+  size_t
+    length;
+
+  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
+  if (quantum_info == (QuantumInfo *) NULL)
+    return(0);
+  length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
+    quantum,destination,&image->exception);
+  quantum_info=DestroyQuantumInfo(quantum_info);
+  return(length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  P o s t s c r i p t G e o m e t r y                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PostscriptGeometry() replaces any page mneumonic with the equivalent size in
+%  picas.
+%
+%  The format of the PostscriptGeometry method is:
+%
+%      char *PostscriptGeometry(const char *page)
+%
+%  A description of each parameter follows.
+%
+%   o  page:  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 *PostscriptGeometry(const char *page)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.1");
+  return(GetPageGeometry(page));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P u s h I m a g e L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PushImageList() adds an image to the end of the list.
+%
+%  The format of the PushImageList method is:
+%
+%      unsigned int PushImageList(Image *images,const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned int PushImageList(Image **images,const Image *image,
+  ExceptionInfo *exception)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  AppendImageToList(images,CloneImageList(image,exception));
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P u s h I m a g e P i x e l s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PushImagePixels() 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 PushImagePixels method is:
+%
+%      size_t PushImagePixels(Image *image,const QuantumType quantum,
+%        const unsigned char *source)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum: Declare which pixel components to transfer (red, green, blue,
+%      opacity, RGB, or RGBA).
+%
+%    o source:  The pixel components are transferred from this buffer.
+%
+*/
+MagickExport size_t PushImagePixels(Image *image,const QuantumType quantum,
+  const unsigned char *source)
+{
+  QuantumInfo
+    *quantum_info;
+
+  size_t
+    length;
+
+  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
+  if (quantum_info == (QuantumInfo *) NULL)
+    return(0);
+  length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,quantum,
+    source,&image->exception);
+  quantum_info=DestroyQuantumInfo(quantum_info);
+  return(length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  Q u a n t i z a t i o n E r r o r                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QuantizationError() 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 QuantizationError method is:
+%
+%      unsigned int QuantizationError(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: Specifies a pointer to an Image structure;  returned from
+%      ReadImage.
+%
+*/
+MagickExport unsigned int QuantizationError(Image *image)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.3");
+  return(GetImageQuantizeError(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%     R a n d o m C h a n n e l T h r e s h o l d I m a g e                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RandomChannelThresholdImage() 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 RandomChannelThresholdImage method is:
+%
+%      unsigned int RandomChannelThresholdImage(Image *image,
+%         const char *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 LOWxHIGH thresholds.
+%      If the string contains 2x2, 3x3, or 4x4, then an ordered
+%      dither of order 2, 3, or 4 will be performed instead.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned int RandomChannelThresholdImage(Image *image,const char
+    *channel,const char *thresholds,ExceptionInfo *exception)
+{
+#define RandomChannelThresholdImageText  "  RandomChannelThreshold image...  "
+
+  double
+    lower_threshold,
+    upper_threshold;
+
+  long
+    count,
+    y;
+
+  RandomInfo
+    *random_info;
+
+  static MagickRealType
+    o2[4]={0.2f, 0.6f, 0.8f, 0.4f}, 
+    o3[9]={0.1f, 0.6f, 0.3f, 0.7f, 0.5f, 0.8f, 0.4f, 0.9f, 0.2f}, 
+    o4[16]={0.1f, 0.7f, 1.1f, 0.3f, 1.0f, 0.5f, 1.5f, 0.8f, 1.4f, 1.6f, 0.6f,
+      1.2f, 0.4f, 0.9f, 1.3f, 0.2f}, 
+    threshold=128;
+
+  unsigned int
+    status;
+
+  unsigned long
+    order;
+
+  /*
+    Threshold 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 (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (thresholds == (const char *) NULL)
+    return(MagickTrue);
+  if (LocaleCompare(thresholds,"2x2") == 0)
+    order=2;
+  else
+    if (LocaleCompare(thresholds,"3x3") == 0)
+      order=3;
+    else
+      if (LocaleCompare(thresholds,"4x4") == 0)
+        order=4;
+      else
+        {
+          order=1;
+          lower_threshold=0;
+          upper_threshold=0;
+          count=sscanf(thresholds,"%lf[/x%%]%lf",&lower_threshold,
+            &upper_threshold);
+          if (strchr(thresholds,'%') != (char *) NULL)
+            {
+              upper_threshold*=(.01*QuantumRange);
+              lower_threshold*=(.01*QuantumRange);
+            }
+          if (count == 1)
+            upper_threshold=(MagickRealType) QuantumRange-lower_threshold;
+        }
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+      "  RandomChannelThresholdImage: channel type=%s",channel);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+      "    Thresholds: %s (%fx%f)",thresholds,lower_threshold,upper_threshold);
+  if (LocaleCompare(channel,"all") == 0 ||
+      LocaleCompare(channel,"intensity") == 0)
+    if (AcquireImageColormap(image,2) == MagickFalse)
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+  random_info=AcquireRandomInfo();
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register IndexPacket
+      index,
+      *__restrict indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    if (LocaleCompare(channel,"all") == 0 ||
+        LocaleCompare(channel,"intensity") == 0)
+      {
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) image->columns; x++)
+          {
+            MagickRealType
+              intensity;
+
+            intensity=(MagickRealType) PixelIntensityToQuantum(q);
+            if (order == 1)
+              {
+                if (intensity < lower_threshold)
+                  threshold=lower_threshold;
+                else if (intensity > upper_threshold)
+                  threshold=upper_threshold;
+                else
+                  threshold=(MagickRealType) (QuantumRange*
+                    GetPseudoRandomValue(random_info));
+              }
+            else if (order == 2)
+              threshold=(MagickRealType) QuantumRange*o2[(x%2)+2*(y%2)];
+            else if (order == 3)
+              threshold=(MagickRealType) QuantumRange*o3[(x%3)+3*(y%3)];
+            else if (order == 4)
+              threshold=(MagickRealType) QuantumRange*o4[(x%4)+4*(y%4)];
+            q->red=q->green=q->blue=(Quantum) (intensity <=
+               threshold ? 0 : QuantumRange);
+            index=(IndexPacket) (intensity <= threshold ? 0 : 1);
+            *indexes++=index;
+            q->red=q->green=q->blue=image->colormap[(long) index].red;
+            q++;
+          }
+      }
+    if (LocaleCompare(channel,"opacity") == 0 ||
+        LocaleCompare(channel,"all") == 0 ||
+        LocaleCompare(channel,"matte") == 0)
+      {
+        if (image->matte != MagickFalse)
+          for (x=0; x < (long) image->columns; x++)
+            {
+              if (order == 1)
+                {
+                  if ((MagickRealType) q->opacity < lower_threshold)
+                    threshold=lower_threshold;
+                  else if ((MagickRealType) q->opacity > upper_threshold)
+                    threshold=upper_threshold;
+                  else
+                    threshold=(MagickRealType) (QuantumRange*
+                      GetPseudoRandomValue(random_info));
+                }
+              else if (order == 2)
+                threshold=(MagickRealType) QuantumRange*o2[(x%2)+2*(y%2)];
+              else if (order == 3)
+                threshold=(MagickRealType) QuantumRange*o3[(x%3)+3*(y%3)];
+              else if (order == 4)
+                threshold=(MagickRealType) QuantumRange*o4[(x%4)+4*(y%4)]/1.7;
+              q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold ?
+                 0 : QuantumRange);
+              q++;
+            }
+      }
+    else
+      {
+        /* To Do: red, green, blue, cyan, magenta, yellow, black */
+        if (LocaleCompare(channel,"intensity") != 0)
+          ThrowBinaryException(OptionError,"UnrecognizedChannelType",
+            image->filename);
+      }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+    if (QuantumTick(y,image->rows) != MagickFalse)
+      {
+        status=MagickMonitor(RandomChannelThresholdImageText,y,image->rows,
+          exception);
+        if (status == MagickFalse)
+          break;
+      }
+  }
+  random_info=DestroyRandomInfo(random_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e a c q u i r e M e m o r y                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReacquireMemory() 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 ReacquireMemory method is:
+%
+%      void ReacquireMemory(void **memory,const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a memory allocation.  On return the pointer
+%      may change but the contents of the original allocation will not.
+%
+%    o size: the new size of the allocated memory.
+%
+*/
+MagickExport void ReacquireMemory(void **memory,const size_t size)
+{
+  void
+    *allocation;
+
+  assert(memory != (void **) NULL);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (*memory == (void *) NULL)
+    {
+      *memory=AcquireMagickMemory(size);
+      return;
+    }
+  allocation=realloc(*memory,size);
+  if (allocation == (void *) NULL)
+    *memory=RelinquishMagickMemory(*memory);
+  *memory=allocation;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e A t t r i b u t e I t e r a t o r                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageAttributeIterator() resets the image attributes iterator.  Use it
+%  in conjunction with GetNextImageAttribute() to iterate over all the values
+%  associated with an image.
+%
+%  The format of the ResetImageAttributeIterator method is:
+%
+%      ResetImageAttributeIterator(const ImageInfo *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void ResetImageAttributeIterator(const Image *image)
+{
+  ResetImagePropertyIterator(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t C a c h e V i e w P i x e l s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCacheViewPixels() 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 SetCacheViewPixels method is:
+%
+%      PixelPacket *SetCacheViewPixels(CacheView *cache_view,const long x,
+%        const long y,const unsigned long columns,const unsigned long rows)
+%
+%  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 PixelPacket *SetCacheViewPixels(CacheView *cache_view,const long x,
+  const long y,const unsigned long columns,const unsigned long rows)
+{
+  PixelPacket
+    *pixels;
+
+  pixels=QueueCacheViewAuthenticPixels(cache_view,x,y,columns,rows,
+    GetCacheViewException(cache_view));
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t C a c h e T h e s h o l d                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCacheThreshold() sets the amount of free memory allocated for the pixel
+%  cache.  Once this threshold is exceeded, all subsequent pixels cache
+%  operations are to/from disk.
+%
+%  The format of the SetCacheThreshold() method is:
+%
+%      void SetCacheThreshold(const size_t threshold)
+%
+%  A description of each parameter follows:
+%
+%    o threshold: the number of megabytes of memory available to the pixel
+%      cache.
+%
+*/
+MagickExport void SetCacheThreshold(const unsigned long size)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.1");
+  (void) SetMagickResourceLimit(MemoryResource,size*1024*1024);
+  (void) SetMagickResourceLimit(MapResource,2*size*1024*1024);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t E x c e p t i o n I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetExceptionInfo() sets the exception severity.
+%
+%  The format of the SetExceptionInfo method is:
+%
+%      MagickBooleanType SetExceptionInfo(ExceptionInfo *exception,
+%        ExceptionType severity)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+%    o severity: the exception severity.
+%
+*/
+MagickExport MagickBooleanType SetExceptionInfo(ExceptionInfo *exception,
+  ExceptionType severity)
+{
+  assert(exception != (ExceptionInfo *) NULL);
+  ClearMagickException(exception);
+  exception->severity=severity;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImage() sets the red, green, and blue components of each pixel to
+%  the image background color and the opacity component to the specified
+%  level of transparency.  The background color is defined by the
+%  background_color member of the image.
+%
+%  The format of the SetImage method is:
+%
+%      void SetImage(Image *image,const Quantum opacity)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o opacity: Set each pixel to this level of transparency.
+%
+*/
+MagickExport void SetImage(Image *image,const Quantum opacity)
+{
+  long
+    y;
+
+  PixelPacket
+    background_color;
+
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.2.0");
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  background_color=image->background_color;
+  if (opacity != OpaqueOpacity)
+    background_color.opacity=opacity;
+  if (background_color.opacity != OpaqueOpacity)
+    {
+      (void) SetImageStorageClass(image,DirectClass);
+      image->matte=MagickTrue;
+    }
+  if ((image->storage_class == PseudoClass) ||
+      (image->colorspace == CMYKColorspace))
+    {
+      /*
+        Set colormapped or CMYK image.
+      */
+      for (y=0; y < (long) image->rows; y++)
+      {
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        q=QueueAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        for (x=0; x < (long) image->columns; x++)
+          *q++=background_color;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) image->columns; x++)
+          indexes[x]=(IndexPacket) 0;
+        if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+          break;
+      }
+      return;
+    }
+  /*
+    Set DirectClass image.
+  */
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+      *q++=background_color;
+    if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+      break;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e A t t r i b u t e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageAttribute() searches the list of image attributes and replaces the
+%  attribute value.  If it is not found in the list, the attribute name
+%  and value is added to the list.   
+%
+%  The format of the SetImageAttribute method is:
+%
+%       MagickBooleanType SetImageAttribute(Image *image,const char *key,
+%         const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o key: the key.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType SetImageAttribute(Image *image,const char *key,
+  const char *value)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.3.1");
+  return(SetImageProperty(image,key,value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageList() inserts an image into the list at the specified position.
+%
+%  The format of the SetImageList method is:
+%
+%      unsigned int SetImageList(Image *images,const Image *image,
+%        const long offset,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o image: the image.
+%
+%    o offset: the position within the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned int SetImageList(Image **images,const Image *image,
+  const long offset,ExceptionInfo *exception)
+{
+  Image
+    *clone;
+
+  register long
+    i;
+
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  clone=CloneImageList(image,exception);
+  while (GetPreviousImageInList(*images) != (Image *) NULL)
+    (*images)=GetPreviousImageInList(*images);
+  for (i=0; i < offset; i++)
+  {
+    if (GetNextImageInList(*images) == (Image *) NULL)
+      return(MagickFalse);
+    (*images)=GetNextImageInList(*images);
+  }
+  InsertImageInList(images,clone);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e P i x e l s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImagePixels() queues a mutable pixel region.
+%  If the region is successfully intialized a pointer to a PixelPacket
+%  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 useful while 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
+%  SetImagePixels() any way it pleases. SetImagePixels() 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 RAM, or in a
+%  memory-mapped file. The returned pointer should *never* be deallocated
+%  by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
+%  the black color component or the colormap indexes (of type IndexPacket)
+%  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
+%  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 SetImagePixels() method is:
+%
+%      PixelPacket *SetImagePixels(Image *image,const long x,const long y,
+%        const unsigned long columns,const unsigned long rows)
+%
+%  A description of each parameter follows:
+%
+%    o pixels: SetImagePixels returns a pointer to the pixels if they are
+%      transferred, otherwise a NULL is returned.
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+*/
+MagickExport PixelPacket *SetImagePixels(Image *image,const long x,const long y,
+  const unsigned long columns,const unsigned long rows)
+{
+  return(QueueAuthenticPixels(image,x,y,columns,rows,&image->exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t M a g i c k R e g i s t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMagickRegistry() sets a blob into the registry and returns a unique ID.
+%  If an error occurs, -1 is returned.
+%
+%  The format of the SetMagickRegistry method is:
+%
+%      long SetMagickRegistry(const RegistryType type,const void *blob,
+%        const size_t length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o type: the registry type.
+%
+%    o blob: the address of a Binary Large OBject.
+%
+%    o length: For a registry type of ImageRegistryType use sizeof(Image)
+%      otherise the blob length in number of bytes.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport long SetMagickRegistry(const RegistryType type,const void *blob,
+  const size_t magick_unused(length),ExceptionInfo *exception)
+{
+  char
+    key[MaxTextExtent];
+
+  MagickBooleanType
+    status;
+
+  static long
+    id = 0;
+
+  (void) FormatMagickString(key,MaxTextExtent,"%ld\n",id);
+  status=SetImageRegistry(type,key,blob,exception);
+  if (status == MagickFalse)
+    return(-1);
+  return(id++);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t M o n i t o r H a n d l e r                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMonitorHandler() sets the monitor handler to the specified method
+%  and returns the previous monitor handler.
+%
+%  The format of the SetMonitorHandler method is:
+%
+%      MonitorHandler SetMonitorHandler(MonitorHandler handler)
+%
+%  A description of each parameter follows:
+%
+%    o handler: Specifies a pointer to a method to handle monitors.
+%
+*/
+
+MagickExport MonitorHandler GetMonitorHandler(void)
+{
+  return(monitor_handler);
+}
+
+MagickExport MonitorHandler SetMonitorHandler(MonitorHandler handler)
+{
+  MonitorHandler
+    previous_handler;
+
+  previous_handler=monitor_handler;
+  monitor_handler=handler;
+  return(previous_handler);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S h i f t I m a g e L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShiftImageList() removes an image from the beginning of the list.
+%
+%  The format of the ShiftImageList method is:
+%
+%      Image *ShiftImageList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *ShiftImageList(Image **images)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  return(RemoveFirstImageFromList(images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S i z e B l o b                                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SizeBlob() returns the current length of the image file or blob.
+%
+%  The format of the SizeBlob method is:
+%
+%      off_t SizeBlob(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o size:  Method SizeBlob returns the current length of the image file
+%      or blob.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickOffsetType SizeBlob(Image *image)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.4.3");
+  return((MagickOffsetType) GetBlobSize(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l i c e I m a g e L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SpliceImageList() removes the images designated by offset and length from
+%  the list and replaces them with the specified list.
+%
+%  The format of the SpliceImageList method is:
+%
+%      Image *SpliceImageList(Image *images,const long offset,
+%        const unsigned long length,const Image *splices,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o offset: the position within the list.
+%
+%    o length: the length of the image list to remove.
+%
+%    o splice: Replace the removed image list with this list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SpliceImageList(Image *images,const long offset,
+  const unsigned long length,const Image *splices,ExceptionInfo *exception)
+{
+  Image
+    *clone;
+
+  register long
+    i;
+
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  clone=CloneImageList(splices,exception);
+  while (GetPreviousImageInList(images) != (Image *) NULL)
+    images=GetPreviousImageInList(images);
+  for (i=0; i < offset; i++)
+  {
+    if (GetNextImageInList(images) == (Image *) NULL)
+      return((Image *) NULL);
+    images=GetNextImageInList(images);
+  }
+  (void) SpliceImageIntoList(&images,length,clone);
+  return(images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i p                                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Strip() strips any whitespace or quotes from the beginning and end of a
+%  string of characters.
+%
+%  The format of the Strip method is:
+%
+%      void Strip(char *message)
+%
+%  A description of each parameter follows:
+%
+%    o message: Specifies an array of characters.
+%
+*/
+MagickExport void Strip(char *message)
+{
+  register char
+    *p,
+    *q;
+
+  assert(message != (char *) NULL);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (*message == '\0')
+    return;
+  if (strlen(message) == 1)
+    return;
+  p=message;
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if ((*p == '\'') || (*p == '"'))
+    p++;
+  q=message+strlen(message)-1;
+  while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
+    q--;
+  if (q > p)
+    if ((*q == '\'') || (*q == '"'))
+      q--;
+  (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
+  message[q-p+1]='\0';
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c C a c h e V i e w                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncCacheView() saves the cache view pixels to the in-memory or disk
+%  cache.  It returns MagickTrue if the pixel region is synced, otherwise
+%  MagickFalse.
+%
+%  The format of the SyncCacheView method is:
+%
+%      MagickBooleanType SyncCacheView(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport MagickBooleanType SyncCacheView(CacheView *cache_view)
+{
+  MagickBooleanType
+    status;
+
+  status=SyncCacheViewAuthenticPixels(cache_view,
+    GetCacheViewException(cache_view));
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c C a c h e V i e w P i x e l s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncCacheViewPixels() 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 SyncCacheViewPixels method is:
+%
+%      MagickBooleanType SyncCacheViewPixels(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SyncCacheViewPixels(CacheView *cache_view)
+{
+  MagickBooleanType
+    status;
+
+  status=SyncCacheViewAuthenticPixels(cache_view,
+    GetCacheViewException(cache_view));
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c I m a g e P i x e l s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImagePixels() saves the 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 SyncImagePixels() method is:
+%
+%      MagickBooleanType SyncImagePixels(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType SyncImagePixels(Image *image)
+{
+  return(SyncAuthenticPixels(image,&image->exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  T e m p o r a r y F i l e n a m e                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TemporaryFilename() replaces the contents of path by a unique path name.
+%
+%  The format of the TemporaryFilename method is:
+%
+%      void TemporaryFilename(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 void TemporaryFilename(char *path)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.6");
+  (void) AcquireUniqueFilename(path);
+  (void) RelinquishUniqueFileResource(path);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T h r e s h o l d I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ThresholdImage() changes the value of individual pixels based on
+%  the intensity of each pixel compared to threshold.  The result is a
+%  high-contrast, two color image.
+%
+%  The format of the ThresholdImage method is:
+%
+%      unsigned int ThresholdImage(Image *image,const double threshold)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o threshold: Define the threshold value
+%
+*/
+MagickExport unsigned int ThresholdImage(Image *image,const double threshold)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  IndexPacket
+    index;
+
+  long
+    y;
+
+  /*
+    Threshold image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.7");
+  if (!AcquireImageColormap(image,2))
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      "UnableToThresholdImage");
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetAuthenticIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=(IndexPacket) ((MagickRealType)
+        PixelIntensityToQuantum(q) <= threshold ? 0 : 1);
+      indexes[x]=index;
+      q->red=image->colormap[(long) index].red;
+      q->green=image->colormap[(long) index].green;
+      q->blue=image->colormap[(long) index].blue;
+      q++;
+    }
+    if (!SyncAuthenticPixels(image,&image->exception))
+      break;
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T h r e s h o l d I m a g e C h a n n e l                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ThresholdImageChannel() changes the value of individual pixels based on
+%  the intensity of each pixel channel.  The result is a high-contrast image.
+%
+%  The format of the ThresholdImageChannel method is:
+%
+%      unsigned int ThresholdImageChannel(Image *image,const char *threshold)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o threshold: define the threshold values.
+%
+*/
+MagickExport unsigned int ThresholdImageChannel(Image *image,
+  const char *threshold)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  MagickPixelPacket
+    pixel;
+
+  GeometryInfo
+    geometry_info;
+
+  IndexPacket
+    index;
+
+  long
+    y;
+
+  unsigned int
+    flags;
+
+  /*
+    Threshold image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (threshold == (const char *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  flags=ParseGeometry(threshold,&geometry_info);
+  pixel.red=geometry_info.rho;
+  if (flags & SigmaValue)
+    pixel.green=geometry_info.sigma;
+  else
+    pixel.green=pixel.red;
+  if (flags & XiValue)
+    pixel.blue=geometry_info.xi;
+  else
+    pixel.blue=pixel.red;
+  if (flags & PsiValue)
+    pixel.opacity=geometry_info.psi;
+  else
+    pixel.opacity=(MagickRealType) OpaqueOpacity;
+  if (flags & PercentValue)
+    {
+      pixel.red*=QuantumRange/100.0f;
+      pixel.green*=QuantumRange/100.0f;
+      pixel.blue*=QuantumRange/100.0f;
+      pixel.opacity*=QuantumRange/100.0f;
+    }
+  if (!(flags & SigmaValue))
+    {
+      if (!AcquireImageColormap(image,2))
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          "UnableToThresholdImage");
+      if (pixel.red == 0)
+        (void) GetImageDynamicThreshold(image,2.0,2.0,&pixel,&image->exception);
+    }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetAuthenticIndexQueue(image);
+    if (IsMagickGray(&pixel) != MagickFalse)
+      for (x=0; x < (long) image->columns; x++)
+      {
+        index=(IndexPacket) ((MagickRealType)
+          PixelIntensityToQuantum(q) <= pixel.red ? 0 : 1);
+        indexes[x]=index;
+        q->red=image->colormap[(long) index].red;
+        q->green=image->colormap[(long) index].green;
+        q->blue=image->colormap[(long) index].blue;
+        q++;
+      }
+    else
+      for (x=0; x < (long) image->columns; x++)
+      {
+        q->red=(Quantum) ((MagickRealType)
+          q->red <= pixel.red ? 0 : QuantumRange);
+        q->green=(Quantum) ((MagickRealType)
+          q->green <= pixel.green ? 0 : QuantumRange);
+        q->blue=(Quantum) ((MagickRealType)
+          q->blue <= pixel.blue ? 0 : QuantumRange);
+        q->opacity=(Quantum) ((MagickRealType)
+          q->opacity <= pixel.opacity ? 0 : QuantumRange);
+        q++;
+      }
+    if (!SyncAuthenticPixels(image,&image->exception))
+      break;
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                              %
+%                                                                              %
+%                                                                              %
++     T r a n s f o r m C o l o r s p a c e                                    %
+%                                                                              %
+%                                                                              %
+%                                                                              %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformColorspace() converts the image to a specified colorspace.
+%  If the image is already in the requested colorspace, no work is performed.
+%  Note that the current colorspace is stored in the image colorspace member.
+%  The transformation matrices are not necessarily the standard ones: the
+%  weights are rescaled to normalize the range of the transformed values to
+%  be [0..QuantumRange].
+%
+%  The format of the TransformColorspace method is:
+%
+%      unsigned int (void) TransformColorspace(Image *image,
+%        const ColorspaceType colorspace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to transform
+%
+%    o colorspace: the desired colorspace.
+%
+*/
+MagickExport unsigned int TransformColorspace(Image *image,
+  const ColorspaceType colorspace)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.6");
+  return(TransformImageColorspace(image,colorspace));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s f o r m H S L                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformHSL() converts a (red, green, blue) to a (hue, saturation,
+%  lightness) triple.
+%
+%  The format of the TransformHSL method is:
+%
+%      void TransformHSL(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 MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport void TransformHSL(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));
+  *hue=0.0;
+  *saturation=0.0;
+  *lightness=(double) ((min+max)/2.0);
+  delta=max-min;
+  if (delta == 0.0)
+    return;
+  *saturation=(double) (delta/((*lightness < 0.5) ? (min+max) :
+    (2.0-max-min)));
+  if (r == max)
+    *hue=(double) (g == min ? 5.0+(max-b)/delta : 1.0-(max-g)/delta);
+  else
+    if (g == max)
+      *hue=(double) (b == min ? 1.0+(max-r)/delta : 3.0-(max-b)/delta);
+    else
+      *hue=(double) (r == min ? 3.0+(max-g)/delta : 5.0-(max-r)/delta);
+  *hue/=6.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s l a t e T e x t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TranslateText() replaces any embedded formatting characters with the
+%  appropriate image attribute and returns the translated text.
+%
+%  The format of the TranslateText method is:
+%
+%      char *TranslateText(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 *TranslateText(const ImageInfo *image_info,Image *image,
+  const char *embed_text)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.2.6");
+  return(InterpretImageProperties(image_info,image,embed_text));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T r a n s p a r e n t I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransparentImage() 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 TransparentImage method is:
+%
+%      MagickBooleanType TransparentImage(Image *image,
+%        const PixelPacket target,const Quantum opacity)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target: the RGB value of the target color.
+%
+%    o opacity: the replacement opacity value.
+%
+*/
+MagickExport MagickBooleanType TransparentImage(Image *image,
+  const PixelPacket target,const Quantum opacity)
+{
+#define TransparentImageTag  "Transparent/Image"
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  /*
+    Make image color transparent.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v6.1.0");
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(image,0,y,image->columns,1,&image->exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (IsColorSimilar(image,q,&target) != MagickFalse)
+        q->opacity=opacity;
+      q++;
+    }
+    if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,TransparentImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U n s h i f t I m a g e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnshiftImageList() adds the image to the beginning of the list.
+%
+%  The format of the UnshiftImageList method is:
+%
+%      unsigned int UnshiftImageList(Image *images,const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned int UnshiftImageList(Image **images,const Image *image,
+  ExceptionInfo *exception)
+{
+  (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.5.2");
+  PrependImageToList(images,CloneImageList(image,exception));
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   V a l i d a t e C o l o r m a p I n d e x                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ValidateColormapIndex() validates the colormap index.  If the index does
+%  not range from 0 to the number of colors in the colormap an exception
+%  issued and 0 is returned.
+%
+%  The format of the ValidateColormapIndex method is:
+%
+%      IndexPacket ValidateColormapIndex(Image *image,const unsigned int index)
+%
+%  A description of each parameter follows:
+%
+%    o index: Method ValidateColormapIndex returns colormap index if it is
+%      valid other an exception issued and 0 is returned.
+%
+%    o image: the image.
+%
+%    o index: This integer is the colormap index.
+%
+*/
+
+MagickExport IndexPacket ValidateColormapIndex(Image *image,
+  const unsigned long index)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DeprecateEvent,GetMagickModule(),"last use: v5.4.4");
+  return(ConstrainColormapIndex(image,index));
+}
+#endif
diff --git a/magick/deprecate.h b/magick/deprecate.h
new file mode 100644
index 0000000..b48eb40
--- /dev/null
+++ b/magick/deprecate.h
@@ -0,0 +1,286 @@
+/*
+  Copyright 1999-2009 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)
+
+#include <stdarg.h>
+#include "magick/blob.h"
+#include "magick/cache-view.h"
+#include "magick/draw.h"
+#include "magick/constitute.h"
+#include "magick/magick-config.h"
+#include "magick/pixel.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/registry.h"
+#include "magick/semaphore.h"
+
+#if !defined(magick_attribute)
+#  if !defined(__GNUC__)
+#    define magick_attribute(x) /*nothing*/
+#  else
+#    define magick_attribute __attribute__
+#  endif
+#endif
+
+#define Downscale(quantum)  ScaleQuantumToChar(quantum)
+#define LABColorspace LabColorspace
+#define Intensity(color)  PixelIntensityToQuantum(color)
+#define LiberateUniqueFileResource(resource) \
+  RelinquishUniqueFileResource(resource)
+#define LiberateMagickResource(resource)  RelinquishMagickResource(resource)
+#define LiberateSemaphore(semaphore)  RelinquishSemaphore(semaphore)
+#define QuantumDepth  MAGICKCORE_QUANTUM_DEPTH
+#define RunlengthEncodedCompression  RLECompression
+#define Upscale(value)  ScaleCharToQuantum(value)
+#define XDownscale(value)  ScaleShortToQuantum(value)
+#define XUpscale(quantum)  ScaleQuantumToShort(quantum)
+
+typedef struct _DoublePixelPacket
+{
+  double
+    red,
+    green,
+    blue,
+    opacity,
+    index;
+} DoublePixelPacket;
+
+typedef enum
+{
+  UndefinedMagickLayerMethod
+} MagickLayerMethod;
+
+typedef MagickOffsetType ExtendedSignedIntegralType;
+typedef MagickSizeType ExtendedUnsignedIntegralType;
+typedef MagickRealType ExtendedRationalType;
+typedef struct _ViewInfo ViewInfo;
+
+typedef MagickBooleanType
+  (*MonitorHandler)(const char *,const MagickOffsetType,const MagickSizeType,
+    ExceptionInfo *);
+
+typedef struct _ImageAttribute
+{
+  char
+    *key,
+    *value;
+                                                                                
+  MagickBooleanType
+    compression;
+                                                                                
+  struct _ImageAttribute
+    *previous,
+    *next;  /* deprecated */
+} ImageAttribute;
+
+extern MagickExport char
+  *AllocateString(const char *),
+  *InterpretImageAttributes(const ImageInfo *,Image *,const char *),
+  *PostscriptGeometry(const char *),
+  *TranslateText(const ImageInfo *,Image *,const char *);
+
+extern MagickExport const ImageAttribute
+  *GetImageAttribute(const Image *,const char *),
+  *GetImageClippingPathAttribute(Image *),
+  *GetNextImageAttribute(const Image *);
+
+extern MagickExport const IndexPacket
+  *AcquireCacheViewIndexes(const CacheView *),
+  *AcquireIndexes(const Image *);
+
+extern MagickExport const PixelPacket
+  *AcquirePixels(const Image *),
+  *AcquireCacheViewPixels(const CacheView *,const long,const long,
+    const unsigned long,const unsigned long,ExceptionInfo *),
+  *AcquireImagePixels(const Image *,const long,const long,const unsigned long,
+    const unsigned long,ExceptionInfo *);
+
+extern MagickExport Image
+  *AllocateImage(const ImageInfo *),
+  *ExtractSubimageFromImage(Image *,const Image *,ExceptionInfo *),
+  *GetImageFromMagickRegistry(const char *,long *id,ExceptionInfo *),
+  *GetImageList(const Image *,const long,ExceptionInfo *),
+  *GetNextImage(const Image *),
+  *GetPreviousImage(const Image *),
+  *FlattenImages(Image *,ExceptionInfo *),
+  *MosaicImages(Image *,ExceptionInfo *),
+  *PopImageList(Image **),
+  *ShiftImageList(Image **),
+  *SpliceImageList(Image *,const long,const unsigned long,const Image *,
+    ExceptionInfo *);
+
+extern MagickExport IndexPacket
+  *GetCacheViewIndexes(CacheView *),
+  *GetIndexes(const Image *),
+  ValidateColormapIndex(Image *,const unsigned long);
+
+extern MagickExport int
+  GetImageGeometry(Image *,const char *,const unsigned int,RectangleInfo *),
+  ParseImageGeometry(const char *,long *,long *,unsigned long *,
+    unsigned long *);
+
+extern MagickExport long
+  GetImageListIndex(const Image *),
+  SetMagickRegistry(const RegistryType,const void *,const size_t,
+    ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  AcquireOneCacheViewPixel(const CacheView *,const long,const long,
+    PixelPacket *,ExceptionInfo *),
+  AcquireOneCacheViewVirtualPixel(const CacheView *,const VirtualPixelMethod,
+    const long,const long,PixelPacket *,ExceptionInfo *),
+  AffinityImage(const QuantizeInfo *,Image *,const Image *),
+  AffinityImages(const QuantizeInfo *,Image *,const Image *),
+  AllocateImageColormap(Image *,const unsigned long),
+  ClipPathImage(Image *,const char *,const MagickBooleanType),
+  CloneImageAttributes(Image *,const Image *),
+  ColorFloodfillImage(Image *,const DrawInfo *,const PixelPacket,const long,
+    const long,const PaintMethod),
+  DeleteImageAttribute(Image *,const char *),
+  DeleteMagickRegistry(const long),
+  DescribeImage(Image *,FILE *,const MagickBooleanType),
+  FormatImageAttribute(Image *,const char *,const char *,...)
+    magick_attribute((format (printf,3,4))),
+  FormatImageAttributeList(Image *,const char *,const char *,va_list)
+    magick_attribute((format (printf,3,0))),
+  FuzzyColorCompare(const Image *,const PixelPacket *,const PixelPacket *),
+  FuzzyOpacityCompare(const Image *,const PixelPacket *,const PixelPacket *),
+  MagickMonitor(const char *,const MagickOffsetType,const MagickSizeType,
+    void *),
+  MapImage(Image *,const Image *,const MagickBooleanType),
+  MapImages(Image *,const Image *,const MagickBooleanType),
+  MatteFloodfillImage(Image *,const PixelPacket,const Quantum,const long,
+    const long,const PaintMethod),
+  OpaqueImage(Image *,const PixelPacket,const PixelPacket),
+  PaintFloodfillImage(Image *,const ChannelType,const MagickPixelPacket *,
+    const long,const long,const DrawInfo *,const PaintMethod),
+  PaintOpaqueImage(Image *,const MagickPixelPacket *,const MagickPixelPacket *),
+  PaintOpaqueImageChannel(Image *,const ChannelType,const MagickPixelPacket *,
+    const MagickPixelPacket *),
+  PaintTransparentImage(Image *,const MagickPixelPacket *,const Quantum),
+  SetExceptionInfo(ExceptionInfo *,ExceptionType),
+  SetImageAttribute(Image *,const char *,const char *),
+  SyncCacheViewPixels(CacheView *),
+  SyncImagePixels(Image *),
+  TransparentImage(Image *,const PixelPacket,const Quantum);
+
+extern MagickExport MagickPixelPacket
+  AcquireOneMagickPixel(const Image *,const long,const long,ExceptionInfo *);
+
+extern MagickExport MonitorHandler
+  GetMonitorHandler(void),
+  SetMonitorHandler(MonitorHandler);
+
+extern MagickExport MagickOffsetType
+  SizeBlob(Image *image);
+
+extern MagickExport MagickPixelPacket
+  InterpolatePixelColor(const Image *,CacheView *,const InterpolatePixelMethod,
+    const double,const double,ExceptionInfo *);
+
+extern MagickExport MagickStatusType
+  ParseSizeGeometry(const Image *,const char *,RectangleInfo *);
+
+extern MagickExport PixelPacket
+  AcquireOnePixel(const Image *,const long,const long,ExceptionInfo *),
+  AcquireOneVirtualPixel(const Image *,const VirtualPixelMethod,const long,
+    const long,ExceptionInfo *),
+  *GetCacheView(CacheView *,const long,const long,const unsigned long,
+    const unsigned long),
+  *GetCacheViewPixels(CacheView *,const long,const long,const unsigned long,
+    const unsigned long),
+  *GetImagePixels(Image *,const long,const long,const unsigned long,
+    const unsigned long),
+  GetOnePixel(Image *,const long,const long),
+  *GetPixels(const Image *),
+  *SetCacheViewPixels(CacheView *,const long,const long,const unsigned long,
+    const unsigned long),
+  *SetImagePixels(Image *,const long,const long,const unsigned long,
+    const unsigned long);
+
+extern MagickExport size_t
+  PopImagePixels(Image *,const QuantumType,unsigned char *),
+  PushImagePixels(Image *,const QuantumType,const unsigned char *);
+
+extern MagickExport unsigned int
+  ChannelImage(Image *,const ChannelType),
+  ChannelThresholdImage(Image *,const char *),
+  DispatchImage(const Image *,const long,const long,const unsigned long,
+    const unsigned long,const char *,const StorageType,void *,ExceptionInfo *),
+  FuzzyColorMatch(const PixelPacket *,const PixelPacket *,const double),
+  GetNumberScenes(const Image *),
+  GetMagickGeometry(const char *,long *,long *,unsigned long *,unsigned long *),
+  IsSubimage(const char *,const unsigned int),
+  PushImageList(Image **,const Image *,ExceptionInfo *),
+  QuantizationError(Image *),
+  RandomChannelThresholdImage(Image *,const char *,const char *,
+    ExceptionInfo *),
+  SetImageList(Image **,const Image *,const long,ExceptionInfo *),
+  TransformColorspace(Image *,const ColorspaceType),
+  ThresholdImage(Image *,const double),
+  ThresholdImageChannel(Image *,const char *),
+  UnshiftImageList(Image **,const Image *,ExceptionInfo *);
+
+extern MagickExport unsigned long
+  GetImageListSize(const Image *);
+
+extern MagickExport CacheView
+  *CloseCacheView(CacheView *),
+  *OpenCacheView(const Image *);
+
+extern MagickExport void
+  *AcquireMemory(const size_t),
+  AllocateNextImage(const ImageInfo *,Image *),
+  *CloneMemory(void *,const void *,const size_t),
+  DestroyImageAttributes(Image *),
+  DestroyImages(Image *),
+  DestroyMagick(void),
+  DestroyMagickRegistry(void),
+  *GetConfigureBlob(const char *,char *,size_t *,ExceptionInfo *),
+  *GetMagickRegistry(const long,RegistryType *,size_t *,ExceptionInfo *),
+  IdentityAffine(AffineMatrix *),
+  LiberateMemory(void **),
+  LiberateSemaphoreInfo(SemaphoreInfo **),
+  FormatString(char *,const char *,...) magick_attribute((format (printf,2,3))),
+  FormatStringList(char *,const char *,va_list)
+    magick_attribute((format (printf,2,0))),
+  HSLTransform(const double,const double,const double,Quantum *,Quantum *,
+    Quantum *),
+  InitializeMagick(const char *),
+  ReacquireMemory(void **,const size_t),
+  ResetImageAttributeIterator(const Image *),
+  SetCacheThreshold(const unsigned long),
+  SetImage(Image *,const Quantum),
+  Strip(char *),
+  TemporaryFilename(char *),
+  TransformHSL(const Quantum,const Quantum,const Quantum,double *,double *,
+    double *);
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/display-private.h b/magick/display-private.h
new file mode 100644
index 0000000..0664fa4
--- /dev/null
+++ b/magick/display-private.h
@@ -0,0 +1,40 @@
+/*
+  Copyright 1999-2009 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 "magick/xwindow-private.h"
+
+extern MagickExport Image
+  *XDisplayImage(Display *,XResourceInfo *,char **,int,Image **,
+    unsigned long *);
+
+extern MagickExport MagickBooleanType XDisplayBackgroundImage(Display *,
+  XResourceInfo *,Image *);
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/display.c b/magick/display.c
new file mode 100644
index 0000000..04346c4
--- /dev/null
+++ b/magick/display.c
@@ -0,0 +1,16000 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/colorspace.h"
+#include "magick/composite.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/delegate.h"
+#include "magick/display.h"
+#include "magick/display-private.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/paint.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/PreRvIcccm.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/shear.h"
+#include "magick/segment.h"
+#include "magick/string_.h"
+#include "magick/transform.h"
+#include "magick/threshold.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#include "magick/widget.h"
+#include "magick/xwindow-private.h"
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+/*
+  Define declarations.
+*/
+#define MaxColors  MagickMin(windows->visual_info->colormap_size,256L)
+
+/*
+  Constant declarations.
+*/
+static const unsigned char
+  HighlightBitmap[8] =
+  {
+    0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
+  },
+  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 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 long
+    i;
+
+  unsigned long
+    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 >= (long) 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 long MagickMax(const long x,const long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline long MagickMin(const long x,const long 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 long
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  unsigned long
+    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) FormatMagickString(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=atof(RotateMenu[entry]);
+                break;
+              }
+            (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
+              angle);
+            if (*angle == '\0')
+              break;
+            degrees=atof(angle);
+            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(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(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 < (long) 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(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 < (long) 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 < (long) 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) FormatMagickString(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;
+
+  unsigned long
+    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) FormatMagickString(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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+          chop_info.width,chop_info.height,chop_info.x,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=(unsigned long) (segment_info.x2-segment_info.x1+1);
+        chop_info.x=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=(unsigned long) (segment_info.x1-segment_info.x2+1);
+            chop_info.x=windows->image.x+segment_info.x2;
+          }
+      }
+    else
+      {
+        chop_info.width=0;
+        chop_info.height=(unsigned long) (segment_info.y2-segment_info.y1+1);
+        chop_info.x=0;
+        chop_info.y=windows->image.y+segment_info.y1;
+        if (segment_info.y1 > segment_info.y2)
+          {
+            chop_info.height=(unsigned long)
+              (segment_info.y1-segment_info.y2+1);
+            chop_info.y=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=(int) (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=(int) (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 PixelPacket
+    *q;
+
+  register long
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  unsigned long
+    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) FormatMagickString(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 **) GetMagickOptions(MagickMethodOptions);
+            if (methods == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,ColorEditMenu[id],
+              (const char **) methods,command);
+            if (entry >= 0)
+              method=(PaintMethod) ParseMagickOption(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=StringToDouble(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=StringToDouble(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)
+      {
+        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 >= (long) (*image)->columns) ||
+            (y_offset >= (long) (*image)->rows))
+          continue;
+        exception=(&(*image)->exception);
+        switch (method)
+        {
+          case PointMethod:
+          default:
+          {
+            /*
+              Update color information using point algorithm.
+            */
+            if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
+              return(MagickFalse);
+            q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            q->red=ScaleShortToQuantum(color.red);
+            q->green=ScaleShortToQuantum(color.green);
+            q->blue=ScaleShortToQuantum(color.blue);
+            (void) SyncAuthenticPixels(*image,&(*image)->exception);
+            break;
+          }
+          case ReplaceMethod:
+          {
+            PixelPacket
+              target;
+
+            /*
+              Update color information using replace algorithm.
+            */
+            (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
+              &(*image)->exception);
+            if ((*image)->storage_class == DirectClass)
+              {
+                for (y=0; y < (long) (*image)->rows; y++)
+                {
+                  q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
+                  if (q == (PixelPacket *) NULL)
+                    break;
+                  for (x=0; x < (int) (*image)->columns; x++)
+                  {
+                    if (IsColorSimilar(*image,q,&target))
+                      {
+                        q->red=ScaleShortToQuantum(color.red);
+                        q->green=ScaleShortToQuantum(color.green);
+                        q->blue=ScaleShortToQuantum(color.blue);
+                      }
+                    q++;
+                  }
+                  if (SyncAuthenticPixels(*image,exception) == MagickFalse)
+                    break;
+                }
+              }
+            else
+              {
+                for (i=0; i < (int) (*image)->colors; i++)
+                  if (IsColorSimilar(*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;
+
+            MagickPixelPacket
+              target;
+
+            /*
+              Update color information using floodfill algorithm.
+            */
+            (void) GetOneVirtualMagickPixel(*image,x_offset,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,
+              x_offset,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 < (long) (*image)->rows; y++)
+            {
+              q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
+              if (q == (PixelPacket *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                q->red=ScaleShortToQuantum(color.red);
+                q->green=ScaleShortToQuantum(color.green);
+                q->blue=ScaleShortToQuantum(color.blue);
+                q++;
+              }
+              if (SyncAuthenticPixels(*image,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+        }
+        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;
+
+  unsigned long
+    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=windows->image.x+x;
+  composite_info.y=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) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
+          composite_info.x,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=GetMagickOptions(MagickComposeOptions);
+            if (operators == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,CompositeMenu[id],
+              (const char **) operators,command);
+            if (entry >= 0)
+              compose=(CompositeOperator) ParseMagickOption(
+                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=atof(factor);
+            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=windows->image.x+event.xbutton.x;
+        composite_info.y=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=windows->image.x+event.xbutton.x;
+            composite_info.y=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=windows->image.x+x;
+        composite_info.y=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=(int) (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=(int) (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=ZoomImage(composite_image,composite_info.width,
+        composite_info.height,&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)
+    {
+      ExceptionInfo
+        *exception;
+
+      int
+        y;
+
+      Quantum
+        opacity;
+
+      register int
+        x;
+
+      register PixelPacket
+        *q;
+
+      /*
+        Create mattes for blending.
+      */
+      (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
+      opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
+        ((long) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
+      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+        return(MagickFalse);
+      image->matte=MagickTrue;
+      exception=(&image->exception);
+      for (y=0; y < (long) image->rows; y++)
+      {
+        q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        for (x=0; x < (int) image->columns; x++)
+        {
+          q->opacity=opacity;
+          q++;
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+    }
+  /*
+    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];
+
+  long
+    x,
+    y;
+
+  MagickStatusType
+    status;
+
+  unsigned long
+    mask,
+    height,
+    width;
+
+  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=>%lux%lu",windows->image.ximage->width,
+      windows->image.ximage->height,width,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) FormatMagickString(geometry,MaxTextExtent,"%s>!",
+      resource_info->image_geometry);
+  else
+    (void) FormatMagickString(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=(unsigned long) (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
+    };
+
+  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 PixelPacket
+    *q;
+
+  unsigned int
+    height,
+    width;
+
+  unsigned long
+    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=windows->image.x+x;
+  crop_info.y=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) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
+          crop_info.x,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=windows->image.x+event.xbutton.x;
+        crop_info.y=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=windows->image.x+x;
+        crop_info.y=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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+            crop_info.width,crop_info.height,crop_info.x,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=windows->image.x+event.xbutton.x;
+          crop_info.y=windows->image.y+event.xbutton.y;
+          break;
+        }
+        case ButtonRelease:
+        {
+          /*
+            User has committed to cropping rectangle.
+          */
+          crop_info.x=windows->image.x+event.xbutton.x;
+          crop_info.y=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=windows->image.x+event.xmotion.x;
+          crop_info.y=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 > (int) windows->image.ximage->width)
+              crop_info.x=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=x;
+            }
+          if (crop_info.y < 0)
+            crop_info.y=0;
+          else
+            if (crop_info.y > (int) windows->image.ximage->height)
+              crop_info.y=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=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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+            crop_info.width,crop_info.height,crop_info.x,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=(long) (crop_info.x+crop_info.width);
+              crop_info.y=(long) (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=(long) (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=(long) (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=(long) (windows->image.width/2L-crop_info.width/2L);
+              crop_info.y=(long) (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=windows->image.x+event.xmotion.x;
+          crop_info.y=windows->image.y+event.xmotion.y;
+          break;
+        }
+        case SelectionRequest:
+        {
+          XSelectionEvent
+            notify;
+
+          XSelectionRequestEvent
+            *request;
+
+          /*
+            Set primary selection.
+          */
+          (void) FormatMagickString(text,MaxTextExtent,"%lux%lu%+ld%+ld",
+            crop_info.width,crop_info.height,crop_info.x,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=(int) (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=(int) (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);
+  for (y=0; y < (long) crop_info.height; y++)
+  {
+    q=GetAuthenticPixels(image,crop_info.x,y+crop_info.y,crop_info.width,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (int) crop_info.width; x++)
+    {
+      q->opacity=(Quantum) TransparentOpacity;
+      q++;
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+  }
+  /*
+    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;
+
+  unsigned long
+    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) FormatMagickString(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 == 6)
+                break;
+              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:
+                    default:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) HighlightBitmap,HighlightWidth,
+                        HighlightHeight);
+                      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) FormatMagickString(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) atoi(WidthsMenu[entry]);
+                  break;
+                }
+              (void) XDialogWidget(display,windows,"Ok","Enter line width:",
+                width);
+              if (*width == '\0')
+                break;
+              line_width=(unsigned int) atoi(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=x;
+    rectangle_info.y=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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+                rectangle_info.width,rectangle_info.height,rectangle_info.x,
+                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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+                rectangle_info.width,rectangle_info.height,rectangle_info.x,
+                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) FormatMagickString(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=event.xbutton.x;
+          rectangle_info.y=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=event.xmotion.x;
+              rectangle_info.y=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 > (int) windows->image.width)
+              rectangle_info.x=(long) 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=x;
+            }
+          if (rectangle_info.y < 0)
+            rectangle_info.y=0;
+          else
+            if (rectangle_info.y > (int) windows->image.height)
+              rectangle_info.y=(long) 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=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=coordinate_info->x;
+        rectangle_info.y=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 (coordinate_info[i].x < rectangle_info.x)
+            rectangle_info.x=MagickMax(coordinate_info[i].x,0);
+          if (coordinate_info[i].y < rectangle_info.y)
+            rectangle_info.y=MagickMax(coordinate_info[i].y,0);
+        }
+        rectangle_info.width=(unsigned long) (x-rectangle_info.x);
+        rectangle_info.height=(unsigned long) (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) FormatMagickString(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 > (int) (line_width/2))
+      draw_info.rectangle_info.x=(long) line_width/2;
+    if (draw_info.rectangle_info.y > (int) (line_width/2))
+      draw_info.rectangle_info.y=(long) 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=(int) (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=(int) (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:
+    {
+      /*
+        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;
+      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;
+
+      long
+        bytes;
+
+      bytes=(long) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
+      if (undo_image != (Image *) NULL)
+        {
+          /*
+            Ensure the undo stash.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 <= (long) (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 > (long) (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=(unsigned long) windows->image.ximage->width;
+      cache_image->rows=(unsigned long) 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=atoi(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=(unsigned long) windows->image.ximage->width;
+          crop_info.height=(unsigned long) 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) FormatMagickString(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;
+
+      long
+        x,
+        y;
+
+      unsigned long
+        height,
+        width;
+
+      /*
+        Resize image.
+      */
+      width=(unsigned long) windows->image.ximage->width;
+      height=(unsigned long) windows->image.ximage->height;
+      x=0;
+      y=0;
+      (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu+0+0",
+        width,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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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=StringToDouble(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=(unsigned long) atol(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=ReduceNoiseImage(*image,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=GetMagickOptions(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) ParseMagickOption(
+        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=StringToDouble(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=StringToDouble(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=StringToDouble(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,
+        (long) (geometry_info.xi+0.5),(long) (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=(long) frame_info.width;
+      frame_info.y=(long) 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) FormatMagickString((*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=GetMagickOptions(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)
+        ParseMagickOption(MagickPreviewOptions,MagickFalse,preview_type);
+      image_info->group=(long) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Preview");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatMagickString((*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) FormatMagickString(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=(long) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Histogram");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatMagickString((*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) FormatMagickString(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=(long) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Matte");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatMagickString((*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) FormatMagickString(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=(unsigned long) atol(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) FormatMagickString(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((unsigned long *) 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;
+
+  unsigned long
+    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=windows->image.x+x;
+  windows->magnify.y=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) FormatMagickString(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=windows->image.x;
+  windows->pan.y=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 PixelPacket
+    *q;
+
+  unsigned int
+    height,
+    width;
+
+  unsigned long
+    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) FormatMagickString(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=GetMagickOptions(MagickMethodOptions);
+            if (methods == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,MatteEditMenu[id],
+              (const char **) methods,command);
+            if (entry >= 0)
+              method=(PaintMethod) ParseMagickOption(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=StringToDouble(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=StringToDouble(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) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
+                  OpaqueOpacity);
+                if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
+                  (void) FormatMagickString(matte,MaxTextExtent,QuantumFormat,
+                    (Quantum) TransparentOpacity);
+                break;
+              }
+            (void) FormatMagickString(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)
+      {
+        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);
+        switch (method)
+        {
+          case PointMethod:
+          default:
+          {
+            /*
+              Update matte information using point algorithm.
+            */
+            q=GetAuthenticPixels(*image,x_offset,y_offset,1,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            q->opacity=(Quantum) atol(matte);
+            (void) SyncAuthenticPixels(*image,exception);
+            break;
+          }
+          case ReplaceMethod:
+          {
+            PixelPacket
+              target;
+
+            /*
+              Update matte information using replace algorithm.
+            */
+            (void) GetOneVirtualPixel(*image,x_offset,y_offset,&target,
+              exception);
+            for (y=0; y < (long) (*image)->rows; y++)
+            {
+              q=GetAuthenticPixels(*image,0,y,(*image)->columns,1,
+                &(*image)->exception);
+              if (q == (PixelPacket *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                if (IsColorSimilar(*image,q,&target))
+                  q->opacity=(Quantum) atol(matte);
+                q++;
+              }
+              if (SyncAuthenticPixels(*image,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+          case FloodfillMethod:
+          case FillToBorderMethod:
+          {
+            DrawInfo
+              *draw_info;
+
+            MagickPixelPacket
+              target;
+
+            /*
+              Update matte information using floodfill algorithm.
+            */
+            (void) GetOneVirtualMagickPixel(*image,x_offset,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.opacity=RoundToQuantum(atof(matte));
+            (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
+              x_offset,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 < (long) (*image)->rows; y++)
+            {
+              q=QueueAuthenticPixels(*image,0,y,(*image)->columns,1,exception);
+              if (q == (PixelPacket *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                q->opacity=(Quantum) atol(matte);
+                q++;
+              }
+              if (SyncAuthenticPixels(*image,exception) == MagickFalse)
+                break;
+            }
+            if (atol(matte) == OpaqueOpacity)
+              (*image)->matte=MagickFalse;
+            break;
+          }
+        }
+        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,MagickFalse,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,(unsigned long) (1000*atol(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) FormatMagickString(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;
+
+  unsigned long
+    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=event->xbutton.x;
+        pan_info.y=event->xbutton.y;
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case ButtonRelease:
+      {
+        /*
+          User has finished panning the image.
+        */
+        pan_info.x=event->xbutton.x;
+        pan_info.y=event->xbutton.y;
+        state|=UpdateConfigurationState | ExitState;
+        break;
+      }
+      case MotionNotify:
+      {
+        pan_info.x=event->xmotion.x;
+        pan_info.y=event->xmotion.y;
+        state|=UpdateConfigurationState;
+      }
+      default:
+        break;
+    }
+    if ((state & UpdateConfigurationState) != 0)
+      {
+        /*
+          Check boundary conditions.
+        */
+        if (pan_info.x < (int) (pan_info.width/2))
+          pan_info.x=0;
+        else
+          pan_info.x=(int) (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=(long)
+              (windows->image.ximage->width-windows->image.width);
+        if (pan_info.y < (long) (pan_info.height/2))
+          pan_info.y=0;
+        else
+          pan_info.y=(long) (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=(long)
+              (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) FormatMagickString(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;
+
+  unsigned long
+    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=windows->image.x+x;
+  paste_info.y=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) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
+          paste_info.x,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=GetMagickOptions(MagickComposeOptions);
+            if (operators == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,PasteMenu[id],
+              (const char **) operators,command);
+            if (entry >= 0)
+              compose=(CompositeOperator) ParseMagickOption(
+                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=windows->image.x+event.xbutton.x;
+        paste_info.y=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=windows->image.x+event.xbutton.x;
+            paste_info.y=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=windows->image.x+x;
+        paste_info.y=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=(int) (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=(int) (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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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;
+
+  unsigned long
+    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=windows->image.x+x;
+  roi_info.y=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) FormatMagickString(text,MaxTextExtent," %+ld%+ld ",
+          roi_info.x,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=windows->image.x+event.xbutton.x;
+        roi_info.y=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=windows->image.x+x;
+        roi_info.y=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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+            roi_info.width,roi_info.height,roi_info.x,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=windows->image.x+event.xbutton.x;
+          roi_info.y=windows->image.y+event.xbutton.y;
+          break;
+        }
+        case ButtonRelease:
+        {
+          /*
+            User has committed to region of interest rectangle.
+          */
+          roi_info.x=windows->image.x+event.xbutton.x;
+          roi_info.y=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=windows->image.x+event.xmotion.x;
+          roi_info.y=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 > (int) windows->image.ximage->width)
+              roi_info.x=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=x;
+            }
+          if (roi_info.y < 0)
+            roi_info.y=0;
+          else
+            if (roi_info.y > (int) windows->image.ximage->height)
+              roi_info.y=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=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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+            roi_info.width,roi_info.height,roi_info.x,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=(int) (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=(int) (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=(long) (roi_info.x+roi_info.width);
+              roi_info.y=(long) (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=(long) (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=(long) (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=(long) (windows->image.width/2L-roi_info.width/2L);
+              roi_info.y=(long) (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=windows->image.x+event.xmotion.x;
+          roi_info.y=windows->image.y+event.xmotion.y;
+          break;
+        }
+        case SelectionRequest:
+        {
+          XSelectionEvent
+            notify;
+
+          XSelectionRequestEvent
+            *request;
+
+          /*
+            Set primary selection.
+          */
+          (void) FormatMagickString(text,MaxTextExtent,"%lux%lu%+ld%+ld",
+            roi_info.width,roi_info.height,roi_info.x,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;
+
+      unsigned long
+        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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
+          break;
+        }
+        case 3:
+        {
+          /*
+            Rotate 270 degrees.
+          */
+          (void) FormatMagickString(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,MagickFalse,&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) FormatMagickString(quality,MaxTextExtent,"%lu",image->quality);
+      status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
+        quality);
+      if (*quality == '\0')
+        return(MagickTrue);
+      image->quality=(unsigned long) atol(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) FormatMagickString(geometry,MaxTextExtent,PSPageGeometry);
+      if (LocaleCompare(image_info->magick,"PDF") == 0)
+        (void) FormatMagickString(geometry,MaxTextExtent,PSPageGeometry);
+      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) FormatMagickString(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=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=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) FormatMagickString(text,MaxTextExtent," %lux%lu%+ld%+ld",
+        crop_info->width,crop_info->height,crop_info->x,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) FormatMagickString(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 PixelPacket
+        *s;
+
+      /*
+        Ensure all the images exist.
+      */
+      tile=0;
+      for (p=image->directory; *p != '\0'; p++)
+      {
+        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);
+        (void) GetOneVirtualPixel(image,0,0,&pixel,exception);
+        for (i=0; i < (int) height; i++)
+        {
+          s=GetAuthenticPixels(image,x_offset,y_offset+i,width,1,exception);
+          if (s == (PixelPacket *) NULL)
+            break;
+          for (j=0; j < (int) width; j++)
+            *s++=pixel;
+          if (SyncAuthenticPixels(image,exception) == MagickFalse)
+            break;
+        }
+        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=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=windows->image.ximage->height-windows->image.height;
+  /*
+    Refresh Image window.
+  */
+  (void) FormatMagickString(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;
+
+  unsigned long
+    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=(unsigned long) 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=x;
+  if (trim_info.x == (int) 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=(unsigned long) (x-trim_info.x+1);
+  /*
+    Crop the top edge.
+  */
+  background=XGetPixel(windows->image.ximage,0,0);
+  trim_info.height=(unsigned long) 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=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=(unsigned long) 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) FormatMagickString(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) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
+    (void *) NULL);
+  images=NewImageList();
+  exception=AcquireExceptionInfo();
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  for (i=0; i < (long) number_files; i++)
+  {
+    (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
+    filelist[i]=DestroyString(filelist[i]);
+    *read_info->magick='\0';
+    (void) CloneString(&read_info->size,DefaultTileGeometry);
+    next_image=ReadImage(read_info,exception);
+    CatchException(exception);
+    if (next_image != (Image *) NULL)
+      {
+        (void) DeleteImageProperty(next_image,"label");
+        (void) SetImageProperty(next_image,"label",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);
+  read_info=DestroyImageInfo(read_info);
+  if (images == (Image *) NULL)
+    {
+      XSetCursorState(display,windows,MagickFalse);
+      ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
+      return((Image *) NULL);
+    }
+  /*
+    Create the Visual Image Directory.
+  */
+  montage_info=CloneMontageInfo(resource_info->image_info,(MontageInfo *) NULL);
+  if (resource_info->font != (char *) NULL)
+    (void) CloneString(&montage_info->font,resource_info->font);
+  (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
+  montage_image=MontageImageList(resource_info->image_info,montage_info,
+    GetFirstImageInList(images),&images->exception);
+  montage_info=DestroyMontageInfo(montage_info);
+  images=DestroyImageList(images);
+  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;
+
+  unsigned long
+    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) FormatMagickString(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,
+    (unsigned long) (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) FormatMagickString(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=window_info.x;
+  geometry_info.y=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[%lu] %lux%lu ",image->filename,image->scene,
+        image->columns,image->rows);
+      if (image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",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) FormatMagickString(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,unsigned long *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,unsigned long *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],
+    *cwd,
+    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;
+
+  unsigned long
+    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[%lu] %lux%lu ",display_image->filename,
+        display_image->scene,display_image->columns,display_image->rows);
+      if (display_image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
+          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,
+    (unsigned long) (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,
+    (unsigned long) (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) FormatMagickString(windows->image.name,MaxTextExtent,
+          "ImageMagick: %s",filename);
+      else
+        (void) FormatMagickString(windows->image.name,MaxTextExtent,
+          "ImageMagick: %s[%lu of %lu]",filename,display_image->scene,
+          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) FormatMagickString(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=(unsigned long) (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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(resource_name,MaxTextExtent,"%s.magnify",
+    resource_info->client_name);
+  windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  (void) FormatMagickString(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) FormatMagickString(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) FormatMagickString(
+                          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=windows->image.x;
+                    vid_info.y=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,
+                    (unsigned long) (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,
+                    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 == (long) windows->image.width) &&
+                (event.xconfigure.height == (long) 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;
+              }
+            /*
+              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)
+          if (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)
+          if (event.xexpose.count == 0)
+            if (windows->magnify.mapped != MagickFalse)
+              {
+                XMakeMagnifyImage(display,windows);
+                break;
+              }
+        if (event.xexpose.window == windows->pan.id)
+          if (event.xexpose.count == 0)
+            {
+              XDrawPanRectangle(display,windows);
+              break;
+            }
+        if (event.xexpose.window == windows->icon.id)
+          if (event.xexpose.count == 0)
+            {
+              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.
+  */
+  cwd=getcwd(working_directory,MaxTextExtent);
+  {
+    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/magick/display.h b/magick/display.h
new file mode 100644
index 0000000..66c6ef3
--- /dev/null
+++ b/magick/display.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2009 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/magick/distort.c b/magick/distort.c
new file mode 100644
index 0000000..c89d799
--- /dev/null
+++ b/magick/distort.c
@@ -0,0 +1,2600 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite-private.h"
+#include "magick/distort.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/hashmap.h"
+#include "magick/image.h"
+#include "magick/list.h"
+#include "magick/matrix.h"
+#include "magick/memory_.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/resample.h"
+#include "magick/resample-private.h"
+#include "magick/registry.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/token.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) ((long) (x+0.5)));
+  return((double) ((long) (x-0.5)));
+}
+
+static unsigned long poly_number_terms(double order)
+{
+  /* Return the number of terms for a 2d polynomial
+     Order must either be an integer, or 1.5 to produce
+     the 2 number_valuesal polyminal 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 determined terms is found.
+   */
+  if ( order < 1 || order > 5 ||
+       ( order != floor(order) && (order-1.5) > MagickEpsilon) )
+    return 0; /* invalid polynomial order */
+  return((unsigned long) floor((order+1)*(order+2)/2));
+}
+
+static double poly_basis_fn(long 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(long n)
+{
+  /* return the result for this polynomial term */
+  switch(n) {
+    case  0:  return(""); /* constant */
+    case  1:  return("*ii");
+    case  2:  return("*jj"); /* affiine      order = 1   terms = 3 */
+    case  3:  return("*ii*jj"); /* biiliinear    order = 1.5 terms = 4 */
+    case  4:  return("*ii*ii");
+    case  5:  return("*jj*jj"); /* quadratiic   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"); /* cubiic       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"); /* quartiic     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"); /* quiintiic     order = 5   terms = 21 */
+  }
+  return( "UNKNOWN" ); /* should never happen */
+}
+static double poly_basis_dx(long 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(long 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 'quadtratic'
+     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 unsigned long number_arguments,const double *arguments,
+%        unsigned long 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, varible 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 unsigned long number_arguments,
+  const double *arguments,unsigned long number_values,ExceptionInfo *exception)
+{
+  double
+    *coeff;
+
+  register unsigned long
+    i;
+
+  unsigned long
+    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 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 %ld CPs'",
+               "Polynomial", 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=11; /* 2*4 coeff plus 3 constants */
+      cp_x = 0;        /* Reverse src/destination for forward mapping */
+      cp_y = 1;
+      cp_values = 2;
+      break;
+    case ShepardsDistortion:
+    case VoronoiColorInterpolate:
+      number_coeff=1;  /* may not be used, but provide some type of return */
+      break;
+    case ArcDistortion:
+      number_coeff=5;
+      break;
+    case ScaleRotateTranslateDistortion:
+    case AffineProjectionDistortion:
+      number_coeff=6;
+      break;
+    case PolarDistortion:
+    case DePolarDistortion:
+      number_coeff=8;
+      number_coeff=8;
+      break;
+    case PerspectiveDistortion:
+    case PerspectiveProjectionDistortion:
+      number_coeff=9;
+      break;
+    case BarrelDistortion:
+    case BarrelInverseDistortion:
+      number_coeff=10;
+      break;
+    case UndefinedDistortion:
+    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 coeffiecents 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 %ld CPs'",
+               "Affine", 1L);
+        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 simultanious 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 : '%s'","Affine",
+                      "Unsolvable Matrix");
+          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 : '%s'","AffineProjection",
+                     "Needs 6 coeff values");
+        return((double *) NULL);
+      }
+      /* FUTURE: trap test for sx*sy-rx*ry == 0 (determinate = 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 alturnative 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 = 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
+           + Can not 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 : '%s'", "ScaleTranslateRotate",
+                     "Needs at least 1 argument");
+        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 : '%s'", "ScaleTranslateRotate",
+                     "Too Many Arguments (7 or less)");
+          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 : '%s'", "ScaleTranslateRotate",
+                     "Zero Scale Given");
+        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];
+
+      unsigned long
+        cp_u = cp_values,
+        cp_v = cp_values+1;
+
+      MagickBooleanType
+        status;
+
+      /* 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 : '%s'","Perspective",
+                    "Unsolvable Matrix");
+        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 : '%s'","PerspectiveProjection",
+                     "Needs 8 coefficient values");
+        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
+            v = c0*x + c1*y + c2*x*y + c3;
+         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  ...
+
+      */
+      double
+        **matrix,
+        **vectors,
+        terms[4];
+
+      MagickBooleanType
+        status;
+
+      /* 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 : '%s'",
+                     *method == BilinearForwardDistortion ?
+                                "BilinearForward" : "BilinearReverse",
+                     "Unsolvable Matrix");
+        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 u,v are in the destination image, NOT the source.
+
+         Reverse mapping however request the reverse of these functions.
+         This requires a full page of algbra to work out the reversed
+         mapping formula, but resolves down to the following...
+
+            a = c2*c5-c1*c6;
+            c8 = c0*c5-c1*c4;
+            c9 = 4*a;
+            c10 = 1/(2*a);
+
+            i = i - c3;   j = j - c7;
+            b = c6*i - c2*j + c8;
+            r = b*b - 2*c9*(c4*ii -  c0*jj);
+
+            y = ( -b + sqrt(r) ) * c10;
+            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.
+
+         For details see Anthony Thyssen <[email protected]>
+
+         constants needed for forward mapped bilinear...
+         */
+         double a = coeff[2]*coeff[5] - coeff[1]*coeff[6];
+         coeff[8] = coeff[0]*coeff[5] - coeff[1]*coeff[4];
+         coeff[9] = 4*a;
+         coeff[10] = 1/(2*a);
+      }
+      return(coeff);
+    }
+    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.
+           + Should be used to generate a 'grid' of bilinear distortions
+             so that it will be 'forward' mapped.
+           + Order 1.5 is fudged to map into a bilinear distortion.
+      */
+      double
+        **matrix,
+        **vectors,
+        *terms;
+
+      unsigned long
+        nterms;   /* number of polynomial terms per number_values */
+
+      register long
+        j;
+
+      MagickBooleanType
+        status;
+
+      /* first two coefficients hold polynomial order information */
+      coeff[0] = arguments[0];
+      coeff[1] = (double) poly_number_terms(arguments[0]);
+      nterms = (unsigned long) 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=0; i < number_arguments; i+=cp_size) {
+        for (j=0; j < (long) 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 : '%s'","Polynomial",
+                     "Unsolvable Matrix");
+        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 : '%s'", "Arc",
+                     "Arc Angle Too Small");
+        return((double *) NULL);
+      }
+      if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+                     "InvalidArgument","%s : '%s'", "Arc",
+                     "Outer Radius Too Small");
+        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 posible 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",
+               *method == PolarDistortion ? "Polar" : "DePolar");
+        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",
+               *method == PolarDistortion ? "Polar" : "DePolar");
+        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 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...
+             A,B,C
+             A,B,C,D
+             A,B,C    X,Y
+             A,B,C,D  X,Y
+             Ax,Bx,Cx,Dx  Ay,By,Cy,Dy
+             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);
+
+      if ( number_arguments != 4 && number_arguments != 6 &&
+           number_arguments != 8 && number_arguments != 10 ) {
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+               "InvalidArgument", "%s : '%s'", "Barrel(Inv)",
+               "number of arguments" );
+        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 - arguments[0] - arguments[1] - arguments[2];
+      else
+         coeff[3] = arguments[3];
+      /* de-normalize the X coefficients */
+      coeff[0] *= pow(rscale,3.0);
+      coeff[1] *= rscale*rscale;
+      coeff[2] *= rscale;
+      /* Y coefficients: as given OR 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 */
+      coeff[8] = ((double)image->columns-1)/2.0 + image->page.x;
+      coeff[9] = ((double)image->rows-1)/2.0    + image->page.y;
+      if ( number_arguments == 5 )  {
+        coeff[8] = arguments[3];
+        coeff[9] = arguments[4];
+      }
+      if ( number_arguments == 6 ) {
+        coeff[8] = arguments[4];
+        coeff[9] = arguments[5];
+      }
+      if ( number_arguments == 10 ) {
+        coeff[8] = arguments[8];
+        coeff[9] = arguments[9];
+      }
+      return(coeff);
+    }
+    case ShepardsDistortion:
+    case VoronoiColorInterpolate:
+    {
+      /* 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 %ld CPs'",
+               "Shepards", 1UL);
+        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 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 unsigned long 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
+%        equivelents 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 unsigned long 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);
+
+  /*
+    Convert input arguments (usally 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 ) {
+    /* always use the 'best fit' viewport */
+    bestfit = MagickTrue;
+  }
+
+  /* Work out the 'best fit', (required for ArcDistortion) */
+  if ( bestfit ) {
+    PointInfo
+      s,d,min,max;
+
+    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=ceil((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] = 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 */
+        geometry.x = geometry.y = 0;
+        geometry.height = (unsigned long) ceil(coeff[0]-coeff[1]);
+        geometry.width = (unsigned long)
+                  ceil((coeff[0]-coeff[1])*(coeff[5]-coeff[4])*0.5);
+        break;
+      }
+      case ShepardsDistortion:
+      case BilinearForwardDistortion:
+      case BilinearReverseDistortion:
+      case PolynomialDistortion:
+      case BarrelDistortion:
+      case BarrelInverseDistortion:
+      default:
+        /* no bestfit available for this distortion */
+        bestfit = MagickFalse;
+        break;
+    }
+    /* Set the output image geometry to calculated 'bestfit'
+       Do not do this for DePolar which needs to be exact for tiling
+    */
+    if ( bestfit && method != DePolarDistortion ) {
+      geometry.x = (long) floor(min.x-0.5);
+      geometry.y = (long) floor(min.y-0.5);
+      geometry.width=(unsigned long) ceil(max.x-geometry.x+0.5);
+      geometry.height=(unsigned long) ceil(max.y-geometry.y+0.5);
+    }
+    /* now that we have a new size lets fit distortion to it exactly */
+    if ( method == DePolarDistortion ) {
+      coeff[6]=(coeff[5]-coeff[4])/geometry.width; /* changed width */
+      coeff[7]=(coeff[0]-coeff[1])/geometry.height; /* should be about 1.0 */
+    }
+  }
+
+  /* The user provided a 'viewport' expert option which may
+     overrides some parts of the current output image geometry.
+     For ArcDistortion, 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 long
+       i;
+    char image_gen[MaxTextExtent];
+    const char *lookup;
+
+    /* Set destination image size and virtual offset */
+    if ( bestfit || viewport_given ) {
+      (void) FormatMagickString(image_gen, MaxTextExtent,"  -size %lux%lu "
+        "-page %+ld%+ld xc: +insert \\\n",geometry.width,geometry.height,
+        geometry.x,geometry.y);
+      lookup="v.p{ xx-v.page.x-.5, yy-v.page.x-.5 }";
+    }
+    else {
+      image_gen[0] = '\0';             /* no destination to generate */
+      lookup = "p{ xx-page.x-.5, yy-page.x-.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);
+        fprintf(stderr, "Affine Projection:\n");
+        fprintf(stderr, "  -distort AffineProjection \\\n      '");
+        for (i=0; i<5; i++)
+          fprintf(stderr, "%lg,", inverse[i]);
+        fprintf(stderr, "%lg'\n", inverse[5]);
+        inverse = (double *) RelinquishMagickMemory(inverse);
+
+        fprintf(stderr, "Affine Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        fprintf(stderr, "       xx=%+lf*ii %+lf*jj %+lf;\n",
+            coeff[0], coeff[1], coeff[2]);
+        fprintf(stderr, "       yy=%+lf*ii %+lf*jj %+lf;\n",
+            coeff[3], coeff[4], coeff[5]);
+        fprintf(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);
+        fprintf(stderr, "Perspective Projection:\n");
+        fprintf(stderr, "  -distort PerspectiveProjection \\\n      '");
+        for (i=0; i<4; i++)
+          fprintf(stderr, "%lg,", inverse[i]);
+        fprintf(stderr, "\n       ");
+        for (; i<7; i++)
+          fprintf(stderr, "%lg,", inverse[i]);
+        fprintf(stderr, "%lg'\n", inverse[7]);
+        inverse = (double *) RelinquishMagickMemory(inverse);
+
+        fprintf(stderr, "Perspective Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        fprintf(stderr, "       rr=%+lf*ii %+lf*jj + 1;\n",
+            coeff[6], coeff[7]);
+        fprintf(stderr, "       xx=(%+lf*ii %+lf*jj %+lf)/rr;\n",
+            coeff[0], coeff[1], coeff[2]);
+        fprintf(stderr, "       yy=(%+lf*ii %+lf*jj %+lf)/rr;\n",
+            coeff[3], coeff[4], coeff[5]);
+        fprintf(stderr, "       rr%s0 ? %s : blue'\n",
+            coeff[8] < 0 ? "<" : ">", lookup);
+        break;
+      }
+
+      case BilinearForwardDistortion:
+        fprintf(stderr, "Bilinear Forward Mapping Equations:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "    i = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
+            coeff[0], coeff[1], coeff[2], coeff[3]);
+        fprintf(stderr, "    j = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
+            coeff[4], coeff[5], coeff[6], coeff[7]);
+        for ( i=8; i<11; i++ )
+          fprintf(stderr, "   c%ld = %+lf", i, coeff[i]);
+        fprintf(stderr, "\n");
+        fprintf(stderr, "Bilinear Forward Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
+            0.5-coeff[3], 0.5-coeff[7]);
+        fprintf(stderr, "       bb=%lf*ii %+lf*jj %+lf;\n",
+            coeff[6], -coeff[2], coeff[8]);
+        fprintf(stderr, "       rt=bb*bb %+lf*(%lf*ii%+lf*jj);\n",
+            -coeff[9], coeff[4], -coeff[0]);
+        fprintf(stderr, "       yy=( -bb + sqrt(rt) ) * %+lf;\n",
+             coeff[10]);
+        fprintf(stderr, "       xx=(ii %+lf*yy)/(%lf %+lf*yy);\n",
+             -coeff[1], coeff[0], coeff[2]);
+        fprintf(stderr, "       (rt < 0 ) ? red : %s'\n", lookup);
+        break;
+
+      case BilinearReverseDistortion:
+        fprintf(stderr, "Bilinear Reverse Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        fprintf(stderr, "       xx=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
+            coeff[0], coeff[1], coeff[2], coeff[3]);
+        fprintf(stderr, "       yy=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
+            coeff[4], coeff[5], coeff[6], coeff[7]);
+        fprintf(stderr, "       %s'\n", lookup);
+        break;
+
+      case PolynomialDistortion:
+      {
+        unsigned long nterms = (unsigned long) coeff[1];
+        fprintf(stderr, "Polynomial (order %lg, terms %lu), FX Equivelent\n",
+                       coeff[0], nterms);
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        fprintf(stderr, "       xx =");
+        for (i=0; i<(long) nterms; i++) {
+          if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n         ");
+          fprintf(stderr, " %+lf%s", coeff[2+i],
+               poly_basis_str(i));
+        }
+        fprintf(stderr, ";\n       yy =");
+        for (i=0; i<(long) nterms; i++) {
+          if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n         ");
+          fprintf(stderr, " %+lf%s", coeff[2+i+nterms],
+               poly_basis_str(i));
+        }
+        fprintf(stderr, ";\n       %s'\n", lookup);
+        break;
+      }
+      case ArcDistortion:
+      {
+        fprintf(stderr, "Arc Distort, Internal Coefficients:\n");
+        for ( i=0; i<5; i++ )
+          fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
+        fprintf(stderr, "Arc Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x; jj=j+page.y;\n");
+        fprintf(stderr, "       xx=(atan2(jj,ii)%+lf)/(2*pi);\n",
+                                  -coeff[0]);
+        fprintf(stderr, "       xx=xx-round(xx);\n");
+        fprintf(stderr, "       xx=xx*%lf %+lf;\n",
+                            coeff[1], coeff[4]);
+        fprintf(stderr, "       yy=(%lf - hypot(ii,jj)) * %lf;\n",
+                            coeff[2], coeff[3]);
+        fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
+        break;
+      }
+      case PolarDistortion:
+      {
+        fprintf(stderr, "Polar Distort, Internal Coefficents\n");
+        for ( i=0; i<8; i++ )
+          fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
+        fprintf(stderr, "Polar Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
+                         -coeff[2], -coeff[3]);
+        fprintf(stderr, "       xx=(atan2(ii,jj)%+lf)/(2*pi);\n",
+                         -(coeff[4]+coeff[5])/2 );
+        fprintf(stderr, "       xx=xx-round(xx);\n");
+        fprintf(stderr, "       xx=xx*2*pi*%lf + v.w/2;\n",
+                         coeff[6] );
+        fprintf(stderr, "       yy=(hypot(ii,jj)%+lf)*%lf;\n",
+                         -coeff[1], coeff[7] );
+        fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
+        break;
+      }
+      case DePolarDistortion:
+      {
+        fprintf(stderr, "DePolar Distort, Internal Coefficents\n");
+        for ( i=0; i<8; i++ )
+          fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
+        fprintf(stderr, "DePolar Distort, FX Equivelent:\n");
+        fprintf(stderr, "%s", image_gen);
+        fprintf(stderr, "  -fx 'aa=(i+.5)*%lf %+lf;\n", coeff[6], -coeff[4] );
+        fprintf(stderr, "       rr=(j+.5)*%lf %+lf;\n", coeff[7], +coeff[1] );
+        fprintf(stderr, "       xx=rr*sin(aa) %+lf;\n", coeff[2] );
+        fprintf(stderr, "       yy=rr*cos(aa) %+lf;\n", coeff[3] );
+        fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
+        break;
+      }
+      case BarrelDistortion:
+      case BarrelInverseDistortion:
+      { double xc,yc;
+        xc = ((double)image->columns-1.0)/2.0 + image->page.x;
+        yc = ((double)image->rows-1.0)/2.0    + image->page.y;
+        fprintf(stderr, "Barrel%s Distort, FX Equivelent:\n",
+             method == BarrelDistortion ? "" : "Inv");
+        fprintf(stderr, "%s", image_gen);
+        if ( fabs(coeff[8]-xc) < 0.1 && fabs(coeff[9]-yc) < 0.1 )
+          fprintf(stderr, "  -fx 'xc=(w-1)/2;  yc=(h-1)/2;\n");
+        else
+          fprintf(stderr, "  -fx 'xc=%lf;  yc=%lf;\n",
+               coeff[8], coeff[9]);
+        fprintf(stderr,
+             "       ii=i-xc;  jj=j-yc;  rr=hypot(ii,jj);\n");
+        fprintf(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]);
+        fprintf(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]);
+        fprintf(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(atof(artifact));
+      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 (SetImageStorageClass(distort_image,DirectClass) == MagickFalse)
+    { /* if image is ColorMapped - change it to DirectClass */
+      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.opacity != OpaqueOpacity)
+    distort_image->matte=MagickTrue;
+
+  { /* ----- MAIN CODE -----
+       Sample the source image to each pixel in the distort image.
+     */
+    long
+      j,
+      progress,
+      status;
+
+    MagickPixelPacket
+      zero;
+
+    ResampleFilter
+      **resample_filter;
+
+    CacheView
+      *distort_view;
+
+    status=MagickTrue;
+    progress=0;
+    GetMagickPixelPacket(distort_image,&zero);
+    resample_filter=AcquireResampleFilterThreadSet(image,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 < (long) distort_image->rows; j++)
+    {
+      double
+        validity;  /* how mathematically valid is this the mapping */
+
+      MagickBooleanType
+        sync;
+
+      MagickPixelPacket
+        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 IndexPacket
+        *__restrict indexes;
+
+      register long
+        i,
+        id;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=QueueCacheViewAuthenticPixels(distort_view,0,j,distort_image->columns,1,
+        exception);
+      if (q == (PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      indexes=GetCacheViewAuthenticIndexQueue(distort_view);
+      pixel=zero;
+
+      /* Define constant scaling vectors for Affine Distortions
+        Other methods are either variable, or use interpolated lookup
+      */
+      id=GetOpenMPThreadId();
+      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;
+
+      GetMagickPixelPacket(distort_image,&invalid);
+      SetMagickPixelPacket(distort_image,&distort_image->matte_color,
+        (IndexPacket *) NULL, &invalid);
+      if (distort_image->colorspace == CMYKColorspace)
+        ConvertRGBToCMYK(&invalid);   /* what about other color spaces? */
+
+      for (i=0; i < (long) 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 )
+                validity = 0.5 - coeff[8]*r/coeff[6];
+            }
+            else if ( abs_r < abs_c7 )
+              validity = 0.5 - coeff[8]*r/coeff[7];
+            /* 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:
+          {
+            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:
+          {
+            double b,r;
+#if 0
+fprintf(stderr, "  d=%lf,%lf => ", d.x,d.y);
+#endif
+            d.x -= coeff[3];  d.y -= coeff[7];
+            b = coeff[6]*d.x - coeff[2]*d.y + coeff[8];
+            r = b*b - coeff[9]*( coeff[4]*d.x - coeff[0]*d.y );
+
+            validity = ( r < 0.0 ) ? 0.0 : 1.0;
+            if ( validity > 0.0 ) {
+              s.y = ( -b + sqrt(r) ) * coeff[10];
+              s.x = ( d.x - coeff[1]*s.y) / ( coeff[0] + coeff[2]*s.y );
+            }
+#if 0
+fprintf(stderr, "s=%lf,%lf   b=%lf  r=%lf\n", s.x,s.y,b,r );
+#endif
+            /* NOTE: the sign of the square root should be -ve for parts
+               where the source image becomes 'flipped' or 'mirrored'.
+               At the moment it will produce 'unknown' results.
+            */
+            /* FUTURE: Horizon handling */
+            /* FUTURE: Scaling factors or Deritives */
+            break;
+          }
+          case PolynomialDistortion:
+          {
+            register long
+              k;
+            long
+              nterms=(long)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  = (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],
+                  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:
+          { /* Rect/Cartesain/Cylinder 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],
+                  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:
+          { /* Polar to Cylindical  */
+            /* 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 BarrelDistortion:
+          case BarrelInverseDistortion:
+          {
+            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 source pixel 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 */
+              s.x=s.y=0.0;
+              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.
+            */
+            unsigned long
+              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 */
+          SetPixelPacket(distort_image,&invalid,q,indexes);
+        }
+        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 */
+            MagickPixelCompositeBlend(&pixel,validity,&invalid,(1.0-validity),
+              &pixel);
+          }
+          SetPixelPacket(distort_image,&pixel,q,indexes);
+        }
+        q++;
+        indexes++;
+      }
+      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;
+        }
+#if 0
+fprintf(stderr, "\n");
+#endif
+    }
+    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,
+%        SparseColorMethod method,const unsigned long 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,SparseColorMethod method,
+  const unsigned long number_arguments,const double *arguments,
+  ExceptionInfo *exception)
+{
+#define SparseColorTag  "Distort/SparseColor"
+
+  DistortImageMethod
+    *distort_method;
+
+  double
+    *coeff;
+
+  Image
+    *sparse_image;
+
+  MagickPixelPacket
+    zero;
+
+  unsigned long
+    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 & IndexChannel   ) number_colors++;
+  if ( channel & OpacityChannel ) number_colors++;
+
+  /*
+    Convert input arguments into mapping coefficients to apply the distortion.
+    Note some Methods may fall back to other simpler methods.
+  */
+  distort_method=(DistortImageMethod *) &method;
+  coeff = GenerateCoefficients(image, distort_method, number_arguments,
+    arguments, number_colors, exception);
+  if ( coeff == (double *) NULL )
+    return((Image *) NULL);
+
+  /* Verbose output */
+  if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
+
+    switch (method) {
+      case BarycentricColorInterpolate:
+      {
+        register long x=0;
+        fprintf(stderr, "Barycentric Sparse Color:\n");
+        if ( channel & RedChannel )
+          fprintf(stderr, "  -channel R -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & GreenChannel )
+          fprintf(stderr, "  -channel G -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & BlueChannel )
+          fprintf(stderr, "  -channel B -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & IndexChannel )
+          fprintf(stderr, "  -channel K -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & OpacityChannel )
+          fprintf(stderr, "  -channel A -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        break;
+      }
+      case BilinearColorInterpolate:
+      {
+        register long x=0;
+        fprintf(stderr, "Bilinear Sparse Color\n");
+        if ( channel & RedChannel )
+          fprintf(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 )
+          fprintf(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 )
+          fprintf(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 & IndexChannel )
+          fprintf(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 & OpacityChannel )
+          fprintf(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:
+        /* unknown, or which are too complex for FX alturnatives */
+        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,image->columns,image->rows,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 ----- */
+    long
+      j,
+      progress;
+
+    MagickBooleanType
+      status;
+
+    CacheView
+      *sparse_view;
+
+    status=MagickTrue;
+    progress=0;
+    GetMagickPixelPacket(sparse_image,&zero);
+    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 < (long) sparse_image->rows; j++)
+    {
+      MagickBooleanType
+        sync;
+
+      MagickPixelPacket
+        pixel;    /* pixel to assign to distorted image */
+
+      register IndexPacket
+        *__restrict indexes;
+
+      register long
+        i;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=QueueCacheViewAuthenticPixels(sparse_view,0,j,sparse_image->columns,
+        1,exception);
+      if (q == (PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+/* FUTURE: get pixel from source image - so channel can replace parts */
+      indexes=GetCacheViewAuthenticIndexQueue(sparse_view);
+      pixel=zero;
+      for (i=0; i < (long) sparse_image->columns; i++)
+      {
+        switch (method)
+        {
+          case BarycentricColorInterpolate:
+          {
+            register long 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 & IndexChannel )
+              pixel.index   = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            if ( channel & OpacityChannel )
+              pixel.opacity = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            break;
+          }
+          case BilinearColorInterpolate:
+          {
+            register long 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 & IndexChannel )
+              pixel.index   = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            if ( channel & OpacityChannel )
+              pixel.opacity = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            break;
+          }
+          case ShepardsColorInterpolate:
+          { /* Shepards Method,uses its own input arguments as coefficients.
+            */
+            unsigned long
+              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 & IndexChannel   ) pixel.index   = 0.0;
+            if ( channel & OpacityChannel ) pixel.opacity = 0.0;
+            denominator = 0.0;
+            for(k=0; k<number_arguments; k+=2+number_colors) {
+              register long x=(long) k+2;
+              double weight =
+                  ((double)i-arguments[ k ])*((double)i-arguments[ k ])
+                + ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
+              if ( weight != 0 )
+                weight = 1/weight;
+              else
+                weight = 1;
+              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 & IndexChannel )
+                pixel.index   += arguments[x++]*weight;
+              if ( channel & OpacityChannel )
+                pixel.opacity += 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 & IndexChannel   ) pixel.index   /= denominator;
+            if ( channel & OpacityChannel ) pixel.opacity /= denominator;
+            break;
+          }
+          case VoronoiColorInterpolate:
+          default:
+          { /* Just use the closest control point you can find! */
+            unsigned long
+              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 long x=(long) 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 & IndexChannel   ) pixel.index   = arguments[x++];
+                if ( channel & OpacityChannel ) pixel.opacity = 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 & IndexChannel   ) pixel.index   *= QuantumRange;
+        if ( channel & OpacityChannel ) pixel.opacity *= QuantumRange;
+        SetPixelPacket(sparse_image,&pixel,q,indexes);
+        q++;
+        indexes++;
+      }
+      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/magick/distort.h b/magick/distort.h
new file mode 100644
index 0000000..ceb584f
--- /dev/null
+++ b/magick/distort.h
@@ -0,0 +1,79 @@
+/*
+  Copyright 1999-2009 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
+
+#include <magick/draw.h>
+
+/*
+  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,
+  BarrelDistortion,
+  BarrelInverseDistortion,
+  ShepardsDistortion,
+  SentinelDistortion
+} DistortImageMethod;
+
+
+typedef enum
+{
+  UndefinedColorInterpolate = UndefinedDistortion,
+  BarycentricColorInterpolate = AffineDistortion,
+  BilinearColorInterpolate = BilinearReverseDistortion,
+  PolynomialColorInterpolate = PolynomialDistortion,
+  ShepardsColorInterpolate = ShepardsDistortion,
+  /* Methods unique to SparseColor(): */
+  VoronoiColorInterpolate = SentinelDistortion
+} SparseColorMethod;
+
+extern MagickExport Image
+  *DistortImage(const Image *,const DistortImageMethod,const unsigned long,
+    const double *,MagickBooleanType,ExceptionInfo *exception),
+  *SparseColorImage(const Image *,const ChannelType,const SparseColorMethod,
+    const unsigned long,const double *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/draw-private.h b/magick/draw-private.h
new file mode 100644
index 0000000..ece53e9
--- /dev/null
+++ b/magick/draw-private.h
@@ -0,0 +1,85 @@
+/*
+  Copyright 1999-2009 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 "magick/cache.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+
+static inline MagickBooleanType GetFillColor(const DrawInfo *draw_info,
+  const long x,const long 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)
+  #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->opacity=OpaqueOpacity;
+  return(status);
+}
+
+static inline MagickBooleanType GetStrokeColor(const DrawInfo *draw_info,
+  const long x,const long 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)
+  #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->opacity=OpaqueOpacity;
+  return(status);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/draw.c b/magick/draw.c
new file mode 100644
index 0000000..95f1456
--- /dev/null
+++ b/magick/draw.c
@@ -0,0 +1,6147 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                        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-2009 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 "magick/studio.h"
+#include "magick/annotate.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/draw-private.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/paint.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/resample.h"
+#include "magick/resample-private.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/token.h"
+#include "magick/transform.h"
+#include "magick/utility.h"
+
+/*
+  Define declarations.
+*/
+#define BezierQuantum  200
+
+/*
+  Typedef declarations.
+*/
+typedef struct _EdgeInfo
+{
+  SegmentInfo
+    bounds;
+
+  MagickRealType
+    scanline;
+
+  PointInfo
+    *points;
+
+  unsigned long
+    number_points;
+
+  long
+    direction;
+
+  MagickBooleanType
+    ghostline;
+
+  unsigned long
+    highwater;
+} EdgeInfo;
+
+typedef struct _ElementInfo
+{
+  MagickRealType
+    cx,
+    cy,
+    major,
+    minor,
+    angle;
+} ElementInfo;
+
+typedef struct _PolygonInfo
+{
+  EdgeInfo
+    *edges;
+
+  unsigned long
+    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 unsigned long
+  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 unsigned long),
+  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 unsigned long,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);
+  else
+    if (draw_info->tile != (Image *) NULL)
+      clone_info->fill_pattern=CloneImage(draw_info->tile,0,0,MagickTrue,
+        &draw_info->tile->exception);
+  clone_info->tile=NewImageList();  /* tile is deprecated */
+  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->interword_spacing=draw_info->interword_spacing;
+  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 long
+        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)
+    {
+      unsigned long
+        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->opacity=draw_info->opacity;
+  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 long
+    i,
+    j;
+
+  (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin active-edge");
+  p=polygon_info->edges;
+  for (i=0; i < (long) polygon_info->number_edges; i++)
+  {
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      edge %lu:",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 < (long) 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 unsigned long number_points)
+{
+  PointInfo
+    point;
+
+  register long
+    i;
+
+  for (i=0; i < (long) (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 long
+    i,
+    n;
+
+  MagickBooleanType
+    ghostline;
+
+  unsigned long
+    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=(unsigned long) 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=(long) (direction > 0);
+            if (direction < 0)
+              ReversePoints(points,(unsigned long) 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=(unsigned long) 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=(long) (direction > 0);
+        if (direction < 0)
+          ReversePoints(points,(unsigned long) 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 == (long) 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=(unsigned long) 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=(long) (direction > 0);
+          if (direction < 0)
+            ReversePoints(points,(unsigned long) 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)
+{
+  long
+    coordinates,
+    start;
+
+  PathInfo
+    *path_info;
+
+  PathInfoCode
+    code;
+
+  PointInfo
+    p,
+    q;
+
+  register long
+    i,
+    n;
+
+  /*
+    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=(long) 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->tile != (Image *) NULL)
+    draw_info->tile=DestroyImage(draw_info->tile);
+  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:
+%
+%      long 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 unsigned long DestroyEdge(PolygonInfo *polygon_info,
+  const unsigned long 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 long
+    i;
+
+  for (i=0; i < (long) 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) || ((unsigned long) (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) || ((unsigned long) (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 long MagickAbsoluteValue(const long 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;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  PointInfo
+    extent[4],
+    min,
+    max,
+    point;
+
+  register long
+    i;
+
+  ResampleFilter
+    **resample_filter;
+
+  SegmentInfo
+    edge;
+
+  CacheView
+    *image_view,
+    *source_view;
+
+  /*
+    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);
+  GetMagickPixelPacket(image,&zero);
+  exception=(&image->exception);
+  resample_filter=AcquireResampleFilterThreadSet(source,MagickTrue,exception);
+  image_view=AcquireCacheView(image);
+  source_view=AcquireCacheView(source);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(status)
+#endif
+  for (y=(long) (edge.y1+0.5); y <= (long) (edge.y2+0.5); y++)
+  {
+    long
+      x_offset;
+
+    MagickPixelPacket
+      composite,
+      pixel;
+
+    PointInfo
+      point;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    SegmentInfo
+      inverse_edge;
+
+    inverse_edge=AffineEdge(source,&inverse_affine,(double) y,&edge);
+    if (inverse_edge.x2 < inverse_edge.x1)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,(long) (inverse_edge.x1+0.5),y,
+      (unsigned long) ((long) (inverse_edge.x2+0.5)-(long) (inverse_edge.x1+
+      0.5)+1),1,exception);
+    if (q == (PixelPacket *) NULL)
+      continue;
+    id=GetOpenMPThreadId();
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    composite=zero;
+    x_offset=0;
+    for (x=(long) (inverse_edge.x1+0.5); x <= (long) (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) ResamplePixelColor(resample_filter[id],point.x,point.y,&pixel);
+      SetMagickPixelPacket(image,q,indexes+x_offset,&composite);
+      MagickPixelCompositeOver(&pixel,pixel.opacity,&composite,
+        composite.opacity,&composite);
+      SetPixelPacket(image,&composite,q,indexes+x_offset);
+      x_offset++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  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;
+
+  long
+    coordinates;
+
+  MagickRealType
+    mid;
+
+  PointInfo
+    end,
+    resolution,
+    start;
+
+  PrimitiveInfo
+    primitive_info[6];
+
+  register long
+    i;
+
+  SegmentInfo
+    bounds;
+
+  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 < (long) 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 < (long) 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=(long) 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=(long) 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) FormatMagickString(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.opacity=(Quantum) TransparentOpacity;
+  (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;
+
+  long
+    j,
+    n;
+
+  MagickRealType
+    length,
+    maximum_length,
+    offset,
+    scale,
+    total_length;
+
+  MagickStatusType
+    status;
+
+  PrimitiveInfo
+    *dash_polygon;
+
+  register long
+    i;
+
+  register MagickRealType
+    dx,
+    dy;
+
+  unsigned long
+    number_vertices;
+
+  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=(unsigned long) 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 < (long) 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) > (long) (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=(unsigned long) 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=(unsigned long) 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=strtod(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;
+
+  long
+    j,
+    k,
+    n;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  MagickRealType
+    angle,
+    factor,
+    primitive_extent;
+
+  PointInfo
+    point;
+
+  PixelPacket
+    start_color;
+
+  PrimitiveInfo
+    *primitive_info;
+
+  PrimitiveType
+    primitive_type;
+
+  register const char
+    *p;
+
+  register long
+    i,
+    x;
+
+  SegmentInfo
+    bounds;
+
+  size_t
+    length;
+
+  unsigned long
+    number_points;
+
+  /*
+    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=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.rx=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ry=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.sy=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.tx=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ty=atof(token);
+            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)
+          {
+            long
+              fill_rule;
+
+            GetMagickToken(q,&q,token);
+            fill_rule=ParseMagickOption(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)
+          {
+            long
+              clip_units;
+
+            GetMagickToken(q,&q,token);
+            clip_units=ParseMagickOption(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)
+          {
+            long
+              decorate;
+
+            GetMagickToken(q,&q,token);
+            decorate=ParseMagickOption(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) FormatMagickString(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.opacity=RoundToQuantum((MagickRealType)
+              QuantumRange*(1.0-factor*atof(token)));
+            break;
+          }
+        if (LocaleCompare("fill-rule",keyword) == 0)
+          {
+            long
+              fill_rule;
+
+            GetMagickToken(q,&q,token);
+            fill_rule=ParseMagickOption(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=atof(token);
+            break;
+          }
+        if (LocaleCompare("font-stretch",keyword) == 0)
+          {
+            long
+              stretch;
+
+            GetMagickToken(q,&q,token);
+            stretch=ParseMagickOption(MagickStretchOptions,MagickFalse,token);
+            if (stretch == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->stretch=(StretchType) stretch;
+            break;
+          }
+        if (LocaleCompare("font-style",keyword) == 0)
+          {
+            long
+              style;
+
+            GetMagickToken(q,&q,token);
+            style=ParseMagickOption(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=(unsigned long) atol(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)
+          {
+            long
+              gravity;
+
+            GetMagickToken(q,&q,token);
+            gravity=ParseMagickOption(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)
+          {
+            long
+              compose;
+
+            primitive_type=ImagePrimitive;
+            GetMagickToken(q,&q,token);
+            compose=ParseMagickOption(MagickComposeOptions,MagickFalse,token);
+            if (compose == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->compose=(CompositeOperator) compose;
+            break;
+          }
+        if (LocaleCompare("interword-spacing",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->interword_spacing=atof(token);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'k':
+      case 'K':
+      {
+        if (LocaleCompare("kerning",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->kerning=atof(token);
+            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]->opacity=RoundToQuantum((MagickRealType)
+              QuantumRange*(1.0-((1.0-QuantumScale*graphic_context[n]->opacity)*
+              factor*atof(token))));
+            graphic_context[n]->fill.opacity=graphic_context[n]->opacity;
+            graphic_context[n]->stroke.opacity=graphic_context[n]->opacity;
+            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) FormatMagickString(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];
+
+                ElementInfo
+                  element;
+
+                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=atof(token);
+                element.cx=atof(token);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.y1=atof(token);
+                element.cy=atof(token);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.x2=atof(token);
+                element.major=atof(token);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.y2=atof(token);
+                element.minor=atof(token);
+                if (LocaleCompare(type,"radial") == 0)
+                  {
+                    GetMagickToken(q,&q,token);
+                    if (*token == ',')
+                      GetMagickToken(q,&q,token);
+                    element.angle=atof(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) FormatMagickString(key,MaxTextExtent,"%s",name);
+                (void) SetImageArtifact(image,key,token);
+                (void) FormatMagickString(key,MaxTextExtent,"%s-geometry",name);
+                (void) FormatMagickString(geometry,MaxTextExtent,"%gx%g%+f%+f",
+                  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=(long) (atof(token)+0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.y=(long) (atof(token)+0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.width=(unsigned long) (atof(token)+0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.height=(unsigned long) (atof(token)+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) FormatMagickString(key,MaxTextExtent,"%s",name);
+                (void) SetImageArtifact(image,key,token);
+                (void) FormatMagickString(key,MaxTextExtent,"%s-geometry",name);
+                (void) FormatMagickString(geometry,MaxTextExtent,
+                  "%lux%lu%+ld%+ld",bounds.width,bounds.height,bounds.x,
+                  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=atof(token);
+            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=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.sy=atof(token);
+            break;
+          }
+        if (LocaleCompare("skewX",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            angle=atof(token);
+            affine.ry=sin(DegreesToRadians(angle));
+            break;
+          }
+        if (LocaleCompare("skewY",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            angle=atof(token);
+            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) FormatMagickString(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=
+              atoi(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]=atof(token);
+                }
+                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=atof(token);
+            break;
+          }
+        if (LocaleCompare("stroke-linecap",keyword) == 0)
+          {
+            long
+              linecap;
+
+            GetMagickToken(q,&q,token);
+            linecap=ParseMagickOption(MagickLineCapOptions,MagickFalse,token);
+            if (linecap == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->linecap=(LineCap) linecap;
+            break;
+          }
+        if (LocaleCompare("stroke-linejoin",keyword) == 0)
+          {
+            long
+              linejoin;
+
+            GetMagickToken(q,&q,token);
+            linejoin=ParseMagickOption(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=(unsigned long) atol(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.opacity=RoundToQuantum((MagickRealType)
+              QuantumRange*(1.0-factor*atof(token)));
+            break;
+          }
+        if (LocaleCompare("stroke-width",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->stroke_width=atof(token);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 't':
+      case 'T':
+      {
+        if (LocaleCompare("text",keyword) == 0)
+          {
+            primitive_type=TextPrimitive;
+            break;
+          }
+        if (LocaleCompare("text-align",keyword) == 0)
+          {
+            long
+              align;
+
+            GetMagickToken(q,&q,token);
+            align=ParseMagickOption(MagickAlignOptions,MagickFalse,token);
+            if (align == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->align=(AlignType) align;
+            break;
+          }
+        if (LocaleCompare("text-anchor",keyword) == 0)
+          {
+            long
+              align;
+
+            GetMagickToken(q,&q,token);
+            align=ParseMagickOption(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=
+              atoi(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=atof(token);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ty=atof(token);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'v':
+      case 'V':
+      {
+        if (LocaleCompare("viewbox",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.x=(long) (atof(token)+0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.y=(long) (atof(token)+0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.width=(unsigned long) (atof(token)+0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.height=(unsigned long) (atof(token)+
+              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=atof(token);
+      GetMagickToken(q,&q,token);
+      if (*token == ',')
+        GetMagickToken(q,&q,token);
+      point.y=atof(token);
+      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 < (long) 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=(unsigned long) 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 < (long) 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+4*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);
+        k=1;
+        t=token;
+        for (s=token; *s != '\0'; s=t)
+        {
+          double
+            value;
+
+          value=strtod(s,&t);
+          if (s == t)
+            {
+              t++;
+              continue;
+            }
+          k++;
+        }
+        length+=k*BezierQuantum;
+        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) (MagickPI*radius))+6*BezierQuantum+360+1;
+        break;
+      }
+      default:
+        break;
+    }
+    if ((unsigned long) (i+length) >= number_points)
+      {
+        /*
+          Resize based on speculative points required by primitive.
+        */
+        while ((unsigned long) (i+length) >= number_points)
+          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;
+          }
+      }
+    switch (primitive_type)
+    {
+      case PointPrimitive:
+      default:
+      {
+        if (primitive_info[j].coordinates != 1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TracePoint(primitive_info+j,primitive_info[j].point);
+        i=(long) (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=(long) (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=(long) (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=(long) (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=(long) (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=(long) (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=(long) (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=(long) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case PathPrimitive:
+      {
+        i=(long) (j+TracePath(primitive_info+j,token));
+        break;
+      }
+      case ColorPrimitive:
+      case MattePrimitive:
+      {
+        long
+          method;
+
+        if (primitive_info[j].coordinates != 1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        GetMagickToken(q,&q,token);
+        method=ParseMagickOption(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 >= (long) 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 long x,const long 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)
+{
+  const GradientInfo
+    *gradient;
+
+  const SegmentInfo
+    *gradient_vector;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    length;
+
+  PointInfo
+    point;
+
+  RectangleInfo
+    bounding_box;
+
+  CacheView
+    *image_view;
+
+  /*
+    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);
+  GetMagickPixelPacket(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 < (long) bounding_box.height; y++)
+  {
+    long
+      j;
+
+    MagickPixelPacket
+      composite,
+      pixel;
+
+    MagickRealType
+      alpha,
+      offset;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      i,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    composite=zero;
+    offset=GetStopColorOffset(gradient,0,y);
+    if (gradient->type != RadialGradient)
+      offset/=length;
+    for (x=bounding_box.x; x < (long) bounding_box.width; x++)
+    {
+      SetMagickPixelPacket(image,q,indexes+x,&pixel);
+      switch (gradient->spread)
+      {
+        case UndefinedSpread:
+        case PadSpread:
+        {
+          if ((x != (long) (gradient_vector->x1+0.5)) ||
+              (y != (long) (gradient_vector->y1+0.5)))
+            {
+              offset=GetStopColorOffset(gradient,x,y);
+              if (gradient->type != RadialGradient)
+                offset/=length;
+            }
+          for (i=0; i < (long) 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 == (long) 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);
+                MagickPixelCompositeBlend(&gradient->stops[i].color,1.0-alpha,
+                  &gradient->stops[j].color,alpha,&composite);
+              }
+          break;
+        }
+        case ReflectSpread:
+        {
+          if ((x != (long) (gradient_vector->x1+0.5)) ||
+              (y != (long) (gradient_vector->y1+0.5)))
+            {
+              offset=GetStopColorOffset(gradient,x,y);
+              if (gradient->type != RadialGradient)
+                offset/=length;
+            }
+          if (offset < 0.0)
+            offset=(-offset);
+          if ((long) fmod(offset,2.0) == 0)
+            offset=fmod(offset,1.0);
+          else
+            offset=1.0-fmod(offset,1.0);
+          for (i=0; i < (long) gradient->number_stops; i++)
+            if (offset < gradient->stops[i].offset)
+              break;
+          if (i == 0)
+            composite=gradient->stops[0].color;
+          else
+            if (i == (long) 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);
+                MagickPixelCompositeBlend(&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 != (long) (gradient_vector->x1+0.5)) ||
+              (y != (long) (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 < (long) gradient->number_stops; i++)
+            if (offset < gradient->stops[i].offset)
+              break;
+          if (i == 0)
+            composite=gradient->stops[0].color;
+          else
+            if (i == (long) 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=(long) gradient->number_stops-1L;
+                  }
+                MagickPixelCompositeBlend(&gradient->stops[i].color,1.0-alpha,
+                  &gradient->stops[j].color,alpha,&composite);
+              }
+          break;
+        }
+      }
+      MagickPixelCompositeOver(&composite,composite.opacity,&pixel,
+        pixel.opacity,&pixel);
+      SetPixelPacket(image,&pixel,q,indexes+x);
+      q++;
+    }
+    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) FormatMagickString(property,MaxTextExtent,"%s",name);
+  path=GetImageArtifact(image,property);
+  if (path == (const char *) NULL)
+    return(MagickFalse);
+  (void) FormatMagickString(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 long
+    i;
+
+  assert(polygon_info != (PolygonInfo **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (polygon_info[i] != (PolygonInfo *) NULL)
+      polygon_info[i]=DestroyPolygonInfo(polygon_info[i]);
+  polygon_info=(PolygonInfo **) RelinquishAlignedMemory(polygon_info);
+  return(polygon_info);
+}
+
+static PolygonInfo **AcquirePolygonThreadSet(const DrawInfo *draw_info,
+  const PrimitiveInfo *primitive_info)
+{
+  PathInfo
+    *path_info;
+
+  register long
+    i;
+
+  PolygonInfo
+    **polygon_info;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  polygon_info=(PolygonInfo **) AcquireAlignedMemory(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 < (long) 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 long x,const long y,
+  MagickRealType *stroke_opacity)
+{
+  long
+    highwater,
+    j,
+    k,
+    number_edges,
+    number_points,
+    winding_number;
+
+  MagickBooleanType
+    quest;
+
+  MagickRealType
+    distance,
+    midpoint,
+    subpath_opacity;
+
+  PointInfo
+    current_point,
+    delta,
+    point,
+    previous_point;
+
+  register const PointInfo
+    *q;
+
+  register EdgeInfo
+    *p;
+
+  register long
+    i;
+
+  register MagickRealType
+    alpha,
+    beta;
+
+  SegmentInfo
+    edge,
+    bounds;
+
+  /*
+    Compute fill & stroke opacity for this (x,y) point.
+  */
+  *stroke_opacity=0.0;
+  subpath_opacity=0.0;
+  winding_number=0;
+  quest=MagickTrue;
+  point.x=(MagickRealType) x;
+  point.y=(MagickRealType) y;
+  edge.x1=0.0;
+  edge.y1=0.0;
+  edge.x2=0.0;
+  edge.y2=0.0;
+  p=polygon_info->edges;
+  number_edges=(long) polygon_info->number_edges;
+  midpoint=mid+0.5;
+  for (j=0; j < number_edges; j++, p++)
+  {
+    bounds=p->bounds;
+    if (point.y <= (bounds.y1-midpoint))
+      break;
+    if (point.y > (bounds.y2+midpoint-MagickEpsilon))
+      {
+        (void) DestroyEdge(polygon_info,(unsigned long) j);
+        number_edges=(long) polygon_info->number_edges;
+        continue;
+      }
+    if (point.y <= bounds.y1)
+      quest=MagickFalse;
+    else
+      if ((quest != MagickFalse) && (point.y <= bounds.y2) &&
+          (point.x > bounds.x1) && (point.x > bounds.x2))
+        winding_number+=p->direction != 0 ? 1 : -1;
+    if ((point.x <= (bounds.x1-midpoint)) ||
+        (point.x > (bounds.x2+midpoint-MagickEpsilon)))
+      continue;
+    highwater=(long) MagickMax((double) p->highwater,1.0);
+    number_points=(long) p->number_points;
+    k=highwater-1;
+    current_point.y=p->points[k].y;
+    for (i=highwater; i < number_points; i++)
+    {
+      previous_point.y=current_point.y;
+      current_point.y=p->points[i].y;
+      if (point.y < (previous_point.y-midpoint))
+        break;
+      if (point.y > (current_point.y+midpoint-MagickEpsilon))
+        continue;
+      q=p->points+i-1;
+      edge.x1=q->x;
+      edge.y1=q->y;
+      edge.x2=(q+1)->x;
+      edge.y2=(q+1)->y;
+      k=i;
+      if (p->scanline != point.y)
+        {
+          p->scanline=point.y;
+          p->highwater=(unsigned long) i;
+          highwater=i;
+        }
+      /*
+        Compute distance between a point and an edge.
+      */
+      delta.x=edge.x2-edge.x1;
+      delta.y=edge.y2-edge.y1;
+      beta=delta.x*(point.x-edge.x1)+delta.y*(point.y-edge.y1);
+      if (beta < 0.0)
+        {
+          delta.x=point.x-edge.x1;
+          delta.y=point.y-edge.y1;
+          distance=delta.x*delta.x+delta.y*delta.y;
+        }
+      else
+        {
+          alpha=delta.x*delta.x+delta.y*delta.y;
+          if (beta > alpha)
+            {
+              delta.x=point.x-edge.x2;
+              delta.y=point.y-edge.y2;
+              distance=delta.x*delta.x+delta.y*delta.y;
+            }
+          else
+            {
+              beta=delta.x*(point.y-edge.y1)-delta.y*(point.x-edge.x1);
+              distance=beta*beta/alpha;
+            }
+        }
+      /*
+        Compute stroke & subpath opacity.
+      */
+      beta=0.0;
+      if (p->ghostline == MagickFalse)
+        {
+          alpha=midpoint;
+          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-midpoint;
+                  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((double) distance);
+        }
+      alpha=beta-1.0;
+      if (subpath_opacity < (alpha*alpha-MagickEpsilon))
+        subpath_opacity=alpha*alpha;
+    }
+    /*
+      Determine winding number.
+    */
+    if ((quest == MagickFalse) || (point.y > bounds.y2) ||
+        (point.x <= bounds.x1) || (point.x > bounds.x2))
+      continue;
+    for (i=highwater; i < number_points; i++)
+      if (point.y <= p->points[i].y)
+        break;
+    if (i != k)
+      {
+        q=p->points+i-1;
+        edge.x1=q->x;
+        edge.y1=q->y;
+        edge.x2=(q+1)->x;
+        edge.y2=(q+1)->y;
+      }
+    if (((edge.x2-edge.x1)*(point.y-edge.y1)) <=
+        ((edge.y2-edge.y1)*(point.x-edge.x1)))
+      winding_number+=p->direction != 0 ? 1 : -1;
+  }
+  /*
+    Compute fill opacity.
+  */
+  if (fill == MagickFalse)
+    return(0.0);
+  if (subpath_opacity >= 1.0)
+    return(1.0);
+  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)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    start,
+    stop,
+    y;
+
+  MagickBooleanType
+    fill,
+    status;
+
+  MagickRealType
+    mid;
+
+  PolygonInfo
+    **polygon_info;
+
+  register EdgeInfo
+    *p;
+
+  register long
+    i;
+
+  SegmentInfo
+    bounds;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) 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 : (unsigned long) (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 : (unsigned long) (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 : (unsigned long) (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 : (unsigned long) (bounds.y2+0.5) >=
+    image->rows ? (double) image->rows-1.0 : bounds.y2;
+  status=MagickTrue;
+  exception=(&image->exception);
+  start=(long) (bounds.x1+0.5);
+  stop=(long) (bounds.x2+0.5);
+  image_view=AcquireCacheView(image);
+  if (primitive_info->coordinates == 1)
+    {
+      /*
+        Draw point.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for shared(status)
+#endif
+      for (y=(long) (bounds.y1+0.5); y <= (long) (bounds.y2+0.5); y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        x=start;
+        q=GetCacheViewAuthenticPixels(image_view,x,y,(unsigned long) (stop-x+1),
+          1,exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for ( ; x <= stop; x++)
+        {
+          if ((x == (long) (primitive_info->point.x+0.5)) &&
+              (y == (long) (primitive_info->point.y+0.5)))
+            (void) GetStrokeColor(draw_info,x,y,q);
+          q++;
+        }
+        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) shared(status)
+#endif
+  for (y=(long) (bounds.y1+0.5); y <= (long) (bounds.y2+0.5); y++)
+  {
+    MagickRealType
+      fill_opacity,
+      stroke_opacity;
+
+    PixelPacket
+      fill_color,
+      stroke_color;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,start,y,(unsigned long) (stop-
+      start+1),1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    id=GetOpenMPThreadId();
+    for (x=start; x <= stop; x++)
+    {
+      /*
+        Fill and/or stroke.
+      */
+      fill_opacity=GetPixelOpacity(polygon_info[id],mid,fill,
+        draw_info->fill_rule,x,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=(MagickRealType) (QuantumRange-fill_opacity*(QuantumRange-
+        fill_color.opacity));
+      MagickCompositeOver(&fill_color,fill_opacity,q,(MagickRealType)
+        q->opacity,q);
+      (void) GetStrokeColor(draw_info,x,y,&stroke_color);
+      stroke_opacity=(MagickRealType) (QuantumRange-stroke_opacity*
+        (QuantumRange-stroke_color.opacity));
+      MagickCompositeOver(&stroke_color,stroke_opacity,q,(MagickRealType)
+        q->opacity,q);
+      q++;
+    }
+    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",
+      "?"
+    };
+
+  long
+    coordinates,
+    y;
+
+  PointInfo
+    p,
+    q,
+    point;
+
+  register long
+    i,
+    x;
+
+  x=(long) (primitive_info->point.x+0.5);
+  y=(long) (primitive_info->point.y+0.5);
+  switch (primitive_info->primitive)
+  {
+    case PointPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "PointPrimitive %ld,%ld %s",x,y,methods[primitive_info->method]);
+      return;
+    }
+    case ColorPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "ColorPrimitive %ld,%ld %s",x,y,methods[primitive_info->method]);
+      return;
+    }
+    case MattePrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "MattePrimitive %ld,%ld %s",x,y,methods[primitive_info->method]);
+      return;
+    }
+    case TextPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "TextPrimitive %ld,%ld",x,y);
+      return;
+    }
+    case ImagePrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "ImagePrimitive %ld,%ld",x,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=(long) primitive_info[i].coordinates;
+        (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+          "    begin open (%ld)",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(),"      %ld: %g,%g",
+        coordinates,point.x,point.y);
+    else
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "      %ld: %g,%g (duplicate)",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 (%ld)",
+        coordinates);
+    else
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end open (%ld)",
+        coordinates);
+  }
+}
+
+MagickExport MagickBooleanType DrawPrimitive(Image *image,
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickStatusType
+    status;
+
+  register long
+    i,
+    x;
+
+  CacheView
+    *image_view;
+
+  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=(long) (primitive_info->point.x+0.5);
+  y=(long) (primitive_info->point.y+0.5);
+  image_view=AcquireCacheView(image);
+  switch (primitive_info->primitive)
+  {
+    case PointPrimitive:
+    {
+      PixelPacket
+        fill_color;
+
+      PixelPacket
+        *q;
+
+      q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+      if (q == (PixelPacket *) NULL)
+        break;
+      (void) GetFillColor(draw_info,x,y,&fill_color);
+      MagickCompositeOver(&fill_color,(MagickRealType) fill_color.opacity,q,
+        (MagickRealType) q->opacity,q);
+      (void) SyncCacheViewAuthenticPixels(image_view,exception);
+      break;
+    }
+    case ColorPrimitive:
+    {
+      switch (primitive_info->method)
+      {
+        case PointMethod:
+        default:
+        {
+          PixelPacket
+            *q;
+
+          q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+          if (q == (PixelPacket *) NULL)
+            break;
+          (void) GetFillColor(draw_info,x,y,q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+          break;
+        }
+        case ReplaceMethod:
+        {
+          MagickBooleanType
+            sync;
+
+          PixelPacket
+            target;
+
+          (void) GetOneCacheViewVirtualPixel(image_view,x,y,&target,exception);
+          for (y=0; y < (long) image->rows; y++)
+          {
+            register PixelPacket
+              *__restrict q;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              if (IsColorSimilar(image,q,&target) == MagickFalse)
+                {
+                  q++;
+                  continue;
+                }
+              (void) GetFillColor(draw_info,x,y,q);
+              q++;
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+        case FloodfillMethod:
+        case FillToBorderMethod:
+        {
+          MagickPixelPacket
+            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;
+
+          for (y=0; y < (long) image->rows; y++)
+          {
+            register long
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              (void) GetFillColor(draw_info,x,y,q);
+              q++;
+            }
+            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;
+
+          PixelPacket
+            *q;
+
+          q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+          if (q == (PixelPacket *) NULL)
+            break;
+          (void) GetFillColor(draw_info,x,y,&pixel);
+          q->opacity=pixel.opacity;
+          (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 < (long) image->rows; y++)
+          {
+            register long
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              if (IsColorSimilar(image,q,&target) == MagickFalse)
+                {
+                  q++;
+                  continue;
+                }
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              q->opacity=pixel.opacity;
+              q++;
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+        case FloodfillMethod:
+        case FillToBorderMethod:
+        {
+          MagickPixelPacket
+            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 < (long) image->rows; y++)
+          {
+            register long
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              q->opacity=pixel.opacity;
+              q++;
+            }
+            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) FormatMagickString(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;
+
+      long
+        x1,
+        y1;
+
+      RectangleInfo
+        geometry;
+
+      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=(long) (primitive_info[1].point.x+0.5);
+      y1=(long) (primitive_info[1].point.y+0.5);
+      if (((x1 != 0L) && (x1 != (long) composite_image->columns)) ||
+          ((y1 != 0L) && (y1 != (long) composite_image->rows)))
+        {
+          char
+            geometry[MaxTextExtent];
+
+          /*
+            Resize image.
+          */
+          (void) FormatMagickString(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->opacity != OpaqueOpacity)
+        (void) SetImageOpacity(composite_image,draw_info->opacity);
+      SetGeometry(image,&geometry);
+      image->gravity=draw_info->gravity;
+      geometry.x=x;
+      geometry.y=y;
+      (void) FormatMagickString(composite_geometry,MaxTextExtent,
+        "%lux%lu%+ld%+ld",composite_image->columns,composite_image->rows,
+        geometry.x,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.opacity != (Quantum) TransparentOpacity))
+        {
+          /*
+            Draw dash polygon.
+          */
+          clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+          clone_info->stroke_width=0.0;
+          clone_info->stroke.opacity=(Quantum) TransparentOpacity;
+          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.opacity != (Quantum) TransparentOpacity))
+        {
+          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=(long) 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.opacity=(Quantum) TransparentOpacity;
+          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 long
+    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.opacity=(Quantum) TransparentOpacity;
+  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->opacity=OpaqueOpacity;
+  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.opacity=(Quantum) TransparentOpacity;
+  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=atof(option);
+  option=GetImageOption(clone_info,"interword-spacing");
+  if (option != (const char *) NULL)
+    draw_info->interword_spacing=atof(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=atof(option);
+  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) ParseMagickOption(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(long n,long k)
+%
+%  A description of each parameter follows:
+%
+%    o n:
+%
+%    o k:
+%
+%
+*/
+static inline MagickRealType Permutate(const long n,const long k)
+{
+  MagickRealType
+    r;
+
+  register long
+    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 long
+    i;
+
+  unsigned long
+    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=(unsigned long) ceil(fabs((double) (theta/(0.5*MagickPI+
+    MagickEpsilon))));
+  p=primitive_info;
+  for (i=0; i < (long) 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 == (long) (arc_segments-1))
+      (p+3)->point=end;
+    TraceBezier(p,4);
+    p+=p->coordinates;
+  }
+  primitive_info->coordinates=(unsigned long) (p-primitive_info);
+  for (i=0; i < (long) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceBezier(PrimitiveInfo *primitive_info,
+  const unsigned long number_coordinates)
+{
+  MagickRealType
+    alpha,
+    *coefficients,
+    weight;
+
+  PointInfo
+    end,
+    point,
+    *points;
+
+  register long
+    i,
+    j;
+
+  register PrimitiveInfo
+    *p;
+
+  unsigned long
+    control_points,
+    quantum;
+
+  /*
+    Allocate coeficients.
+  */
+  quantum=number_coordinates;
+  for (i=0; i < (long) number_coordinates; i++)
+  {
+    for (j=i+1; j < (long) number_coordinates; j++)
+    {
+      alpha=fabs(primitive_info[j].point.x-primitive_info[i].point.x);
+      if (alpha > (MagickRealType) quantum)
+        quantum=(unsigned long) alpha;
+      alpha=fabs(primitive_info[j].point.y-primitive_info[i].point.y);
+      if (alpha > (MagickRealType) quantum)
+        quantum=(unsigned long) alpha;
+    }
+  }
+  quantum=(unsigned long) 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 < (long) number_coordinates; i++)
+    coefficients[i]=Permutate((long) number_coordinates-1,i);
+  weight=0.0;
+  for (i=0; i < (long) 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 < (long) 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 < (long) control_points; i++)
+  {
+    TracePoint(p,points[i]);
+    p+=p->coordinates;
+  }
+  TracePoint(p,end);
+  p+=p->coordinates;
+  primitive_info->coordinates=(unsigned long) (p-primitive_info);
+  for (i=0; i < (long) 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 long
+    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 < (MagickPI/8.0))
+    step=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=(unsigned long) (p-primitive_info);
+  for (i=0; i < (long) 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 unsigned long 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 long
+    i;
+
+  unsigned long
+    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=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          arc.y=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          angle=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          large_arc=atoi(token) != 0 ? MagickTrue : MagickFalse;
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          sweep=atoi(token) != 0 ? MagickTrue : MagickFalse;
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          x=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=atof(token);
+          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=atof(token);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=atof(token);
+            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=atof(token);
+          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=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=atof(token);
+          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=(unsigned long) (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=atof(token);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=atof(token);
+          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 (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=atof(token);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=atof(token);
+            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=atof(token);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=atof(token);
+            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=atof(token);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=atof(token);
+            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=atof(token);
+          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=(unsigned long) (q-primitive_info);
+        number_coordinates+=primitive_info->coordinates;
+        primitive_info=q;
+        z_count++;
+        break;
+      }
+      default:
+      {
+        if (isalpha((int) ((unsigned char) attribute)) != 0)
+          (void) fprintf(stderr,"attribute not recognized: %c\n",attribute);
+        break;
+      }
+    }
+  }
+  primitive_info->coordinates=(unsigned long) (q-primitive_info);
+  number_coordinates+=primitive_info->coordinates;
+  for (i=0; i < (long) 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 long
+    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=(unsigned long) (p-primitive_info);
+  for (i=0; i < (long) 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 long
+    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=(unsigned long) (p-primitive_info);
+  for (i=0; i < (long) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceSquareLinecap(PrimitiveInfo *primitive_info,
+  const unsigned long number_vertices,const MagickRealType offset)
+{
+  MagickRealType
+    distance;
+
+  long
+    j;
+
+  register MagickRealType
+    dx,
+    dy;
+
+  register long
+    i;
+
+  dx=0.0;
+  dy=0.0;
+  for (i=1; i < (long) 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 == (long) number_vertices)
+    i=(long) 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=(long) 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;
+
+  long
+    j,
+    n,
+    p,
+    q;
+
+  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 long
+    i;
+
+  unsigned long
+    arc_segments,
+    max_strokes,
+    number_vertices;
+
+  /*
+    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 < (long) 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 == (long) number_vertices)
+    n=(long) 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=(long) n+1; i < (long) 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 >= (long) (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=(unsigned long) 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 < (long) 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=(unsigned long) ceil((double) ((theta.p-theta.q)/
+            (2.0*sqrt((double) (1.0/mid)))));
+          path_p[p++]=box_p[1];
+          for (j=1; j < (long) 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 < (long) 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 < (long) (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=(unsigned long) (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/magick/draw.h b/magick/draw.h
new file mode 100644
index 0000000..9098127
--- /dev/null
+++ b/magick/draw.h
@@ -0,0 +1,384 @@
+/*
+  Copyright 1999-2009 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 "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/pixel.h"
+#include "magick/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
+{
+  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
+{
+  MagickPixelPacket
+    color;
+
+  MagickRealType
+    offset;
+} StopInfo;
+
+typedef struct _GradientInfo
+{
+  GradientType
+    type;
+
+  RectangleInfo
+    bounding_box;
+
+  SegmentInfo
+    gradient_vector;
+
+  StopInfo
+    *stops;
+
+  unsigned long
+    number_stops;
+
+  SpreadMethod
+    spread;
+
+  MagickBooleanType
+    debug;
+
+  unsigned long
+    signature;
+
+  PointInfo
+    center;
+
+  MagickRealType
+    radius;
+} GradientInfo;
+
+typedef struct _ElementReference
+{
+  char
+    *id;
+
+  ReferenceType
+    type;
+
+  GradientInfo
+    gradient;
+
+  unsigned long
+    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,
+    *tile,
+    *stroke_pattern;
+
+  MagickBooleanType
+    stroke_antialias,
+    text_antialias;
+
+  FillRule
+    fill_rule;
+
+  LineCap
+    linecap;
+
+  LineJoin
+    linejoin;
+
+  unsigned long
+    miterlimit;
+
+  double
+    dash_offset;
+
+  DecorationType
+    decorate;
+
+  CompositeOperator
+    compose;
+
+  char
+    *text;
+
+  unsigned long
+    face;
+
+  char
+    *font,
+    *metrics,
+    *family;
+
+  StyleType
+    style;
+
+  StretchType
+    stretch;
+
+  unsigned long
+    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
+    opacity;
+
+  MagickBooleanType
+    render;
+
+  ElementReference
+    element_reference;
+
+  MagickBooleanType
+    debug;
+
+  unsigned long
+    signature;
+
+  double
+    kerning,
+    interword_spacing;
+} DrawInfo;
+
+typedef struct _PrimitiveInfo
+{
+  PointInfo
+    point;
+
+  unsigned long
+    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/magick/effect.c b/magick/effect.c
new file mode 100644
index 0000000..6b74def
--- /dev/null
+++ b/magick/effect.c
@@ -0,0 +1,4760 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/draw.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/effect.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/montage.h"
+#include "magick/paint.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/random-private.h"
+#include "magick/resample.h"
+#include "magick/resample-private.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/segment.h"
+#include "magick/shear.h"
+#include "magick/signature-private.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/transform.h"
+#include "magick/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)
+
+  double
+    **kernel;
+
+  Image
+    *blur_image,
+    *edge_image,
+    *gaussian_image;
+
+  long
+    j,
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    alpha,
+    bias,
+    normalize;
+
+  register long
+    i,
+    u,
+    v;
+
+  unsigned long
+    width;
+
+  CacheView
+    *blur_view,
+    *edge_view,
+    *image_view;
+
+  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 < (long) width; i+=2)
+  {
+    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+      sizeof(**kernel));
+    if (kernel[i] == (double *) NULL)
+      break;
+    j=0;
+    for (v=(-((long) (width-i)/2)); v <= (long) ((width-i)/2); v++)
+    {
+      for (u=(-((long) (width-i)/2)); u <= (long) ((width-i)/2); u++)
+      {
+        alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+        kernel[i][j]=(double) (alpha/(2.0*MagickPI*MagickSigma*MagickSigma));
+        j++;
+      }
+    }
+    normalize=0.0;
+    for (j=0; j < (long) ((width-i)*(width-i)); j++)
+      normalize+=kernel[i][j];
+    if (fabs(normalize) <= MagickEpsilon)
+      normalize=1.0;
+    normalize=1.0/normalize;
+    for (j=0; j < (long) ((width-i)*(width-i)); j++)
+      kernel[i][j]=(double) (normalize*kernel[i][j]);
+  }
+  if (i < (long) 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;
+  bias=image->bias;
+  GetMagickPixelPacket(image,&zero);
+  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) shared(progress,status)
+#endif
+  for (y=0; y < (long) blur_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict r;
+
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (x=0; x < (long) blur_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        alpha,
+        gamma;
+
+      register const double
+        *__restrict k;
+
+      register long
+        i,
+        u,
+        v;
+
+      gamma=0.0;
+      i=(long) (width*QuantumScale*PixelIntensity(r)+0.5);
+      if (i < 0)
+        i=0;
+      else
+        if (i > (long) width)
+          i=(long) width;
+      if ((i & 0x01) != 0)
+        i--;
+      p=GetCacheViewVirtualPixels(image_view,x-((long) (width-i)/2L),y-(long)
+        ((width-i)/2L),width-i,width-i,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      pixel=zero;
+      k=kernel[i];
+      for (v=0; v < (long) (width-i); v++)
+      {
+        for (u=0; u < (long) (width-i); u++)
+        {
+          alpha=1.0;
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte != MagickFalse))
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+          if ((channel & RedChannel) != 0)
+            pixel.red+=(*k)*alpha*p->red;
+          if ((channel & GreenChannel) != 0)
+            pixel.green+=(*k)*alpha*p->green;
+          if ((channel & BlueChannel) != 0)
+            pixel.blue+=(*k)*alpha*p->blue;
+          if ((channel & OpacityChannel) != 0)
+            pixel.opacity+=(*k)*p->opacity;
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            pixel.index+=(*k)*alpha*indexes[x+(width-i)*v+u];
+          gamma+=(*k)*alpha;
+          k++;
+          p++;
+        }
+      }
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      if ((channel & RedChannel) != 0)
+        q->red=RoundToQuantum(gamma*pixel.red+bias);
+      if ((channel & GreenChannel) != 0)
+        q->green=RoundToQuantum(gamma*pixel.green+bias);
+      if ((channel & BlueChannel) != 0)
+        q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=RoundToQuantum(pixel.opacity+bias);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        blur_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+      q++;
+      r++;
+    }
+    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 < (long) 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)
+
+  double
+    **kernel;
+
+  Image
+    *sharp_image,
+    *edge_image,
+    *gaussian_image;
+
+  long
+    j,
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    alpha,
+    bias,
+    normalize;
+
+  register long
+    i,
+    u,
+    v;
+
+  unsigned long
+    width;
+
+  CacheView
+    *sharp_view,
+    *edge_view,
+    *image_view;
+
+  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 < (long) width; i+=2)
+  {
+    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+      sizeof(**kernel));
+    if (kernel[i] == (double *) NULL)
+      break;
+    j=0;
+    for (v=(-((long) (width-i)/2)); v <= (long) ((width-i)/2); v++)
+    {
+      for (u=(-((long) (width-i)/2)); u <= (long) ((width-i)/2); u++)
+      {
+        alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+        kernel[i][j]=(double) (-alpha/(2.0*MagickPI*MagickSigma*MagickSigma));
+        j++;
+      }
+    }
+    normalize=0.0;
+    for (j=0; j < (long) ((width-i)*(width-i)); j++)
+      normalize+=kernel[i][j];
+    if (fabs(normalize) <= MagickEpsilon)
+      normalize=1.0;
+    normalize=1.0/normalize;
+    for (j=0; j < (long) ((width-i)*(width-i)); j++)
+      kernel[i][j]=(double) (normalize*kernel[i][j]);
+  }
+  if (i < (long) 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;
+  bias=image->bias;
+  GetMagickPixelPacket(image,&zero);
+  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) shared(progress,status)
+#endif
+  for (y=0; y < (long) sharp_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict r;
+
+    register IndexPacket
+      *__restrict sharp_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    sharp_indexes=GetCacheViewAuthenticIndexQueue(sharp_view);
+    for (x=0; x < (long) sharp_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        alpha,
+        gamma;
+
+      register const double
+        *__restrict k;
+
+      register long
+        i,
+        u,
+        v;
+
+      gamma=0.0;
+      i=(long) (width*(QuantumRange-QuantumScale*PixelIntensity(r))+0.5);
+      if (i < 0)
+        i=0;
+      else
+        if (i > (long) width)
+          i=(long) width;
+      if ((i & 0x01) != 0)
+        i--;
+      p=GetCacheViewVirtualPixels(image_view,x-((long) (width-i)/2L),y-(long)
+        ((width-i)/2L),width-i,width-i,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      k=kernel[i];
+      pixel=zero;
+      for (v=0; v < (long) (width-i); v++)
+      {
+        for (u=0; u < (long) (width-i); u++)
+        {
+          alpha=1.0;
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte != MagickFalse))
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+          if ((channel & RedChannel) != 0)
+            pixel.red+=(*k)*alpha*p->red;
+          if ((channel & GreenChannel) != 0)
+            pixel.green+=(*k)*alpha*p->green;
+          if ((channel & BlueChannel) != 0)
+            pixel.blue+=(*k)*alpha*p->blue;
+          if ((channel & OpacityChannel) != 0)
+            pixel.opacity+=(*k)*p->opacity;
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            pixel.index+=(*k)*alpha*indexes[x+(width-i)*v+u];
+          gamma+=(*k)*alpha;
+          k++;
+          p++;
+        }
+      }
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      if ((channel & RedChannel) != 0)
+        q->red=RoundToQuantum(gamma*pixel.red+bias);
+      if ((channel & GreenChannel) != 0)
+        q->green=RoundToQuantum(gamma*pixel.green+bias);
+      if ((channel & BlueChannel) != 0)
+        q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=RoundToQuantum(pixel.opacity+bias);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        sharp_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+      q++;
+      r++;
+    }
+    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 < (long) 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(unsigned long width,const MagickRealType sigma)
+{
+#define KernelRank 3
+
+  double
+    *kernel;
+
+  long
+    bias;
+
+  MagickRealType
+    alpha,
+    normalize;
+
+  register long
+    i;
+
+  /*
+    Generate a 1-D convolution kernel.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    return(0);
+  (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
+  bias=KernelRank*(long) width/2;
+  for (i=(-bias); i <= bias; i++)
+  {
+    alpha=exp((-((double) (i*i))/(double) (2.0*KernelRank*KernelRank*
+      MagickSigma*MagickSigma)));
+    kernel[(i+bias)/KernelRank]+=(double) (alpha/(MagickSQ2PI*sigma));
+  }
+  normalize=0.0;
+  for (i=0; i < (long) width; i++)
+    normalize+=kernel[i];
+  for (i=0; i < (long) 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"
+
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  long
+    progress,
+    x,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    bias;
+
+  register long
+    i;
+
+  unsigned long
+    width;
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  /*
+    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 %ld kernel:",width);
+      message=AcquireString("");
+      k=kernel;
+      for (i=0; i < (long) width; i++)
+      {
+        *message='\0';
+        (void) FormatMagickString(format,MaxTextExtent,"%ld: ",i);
+        (void) ConcatenateString(&message,format);
+        (void) FormatMagickString(format,MaxTextExtent,"%g ",*k++);
+        (void) ConcatenateString(&message,format);
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  /*
+    Blur rows.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(image,&zero);
+  bias=image->bias;
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) blur_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y,image->columns+
+      width,1,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (x=0; x < (long) blur_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      register const double
+        *__restrict k;
+
+      register const PixelPacket
+        *__restrict kernel_pixels;
+
+      register long
+        i;
+
+      pixel=zero;
+      k=kernel;
+      kernel_pixels=p;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (long) width; i++)
+          {
+            pixel.red+=(*k)*kernel_pixels->red;
+            pixel.green+=(*k)*kernel_pixels->green;
+            pixel.blue+=(*k)*kernel_pixels->blue;
+            k++;
+            kernel_pixels++;
+          }
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.opacity+=(*k)*kernel_pixels->opacity;
+                k++;
+                kernel_pixels++;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=kernel;
+              kernel_indexes=indexes;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.index+=(*k)*(*kernel_indexes);
+                k++;
+                kernel_indexes++;
+              }
+              blur_indexes[x]=RoundToQuantum(pixel.index+bias);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < (long) width; i++)
+          {
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+              kernel_pixels->opacity));
+            pixel.red+=(*k)*alpha*kernel_pixels->red;
+            pixel.green+=(*k)*alpha*kernel_pixels->green;
+            pixel.blue+=(*k)*alpha*kernel_pixels->blue;
+            gamma+=(*k)*alpha;
+            k++;
+            kernel_pixels++;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(gamma*pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(gamma*pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.opacity+=(*k)*kernel_pixels->opacity;
+                k++;
+                kernel_pixels++;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=kernel;
+              kernel_pixels=p;
+              kernel_indexes=indexes;
+              for (i=0; i < (long) width; i++)
+              {
+                alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                  kernel_pixels->opacity));
+                pixel.index+=(*k)*alpha*(*kernel_indexes);
+                k++;
+                kernel_pixels++;
+                kernel_indexes++;
+              }
+              blur_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+            }
+        }
+      p++;
+      q++;
+    }
+    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 shared(progress,status)
+#endif
+  for (x=0; x < (long) blur_image->columns; x++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      y;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,x,-((long) width/2L),1,image->rows+
+      width,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,x,0,1,blur_image->rows,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (y=0; y < (long) blur_image->rows; y++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      register const double
+        *__restrict k;
+
+      register const PixelPacket
+        *__restrict kernel_pixels;
+
+      register long
+        i;
+
+      pixel=zero;
+      k=kernel;
+      kernel_pixels=p;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (long) width; i++)
+          {
+            pixel.red+=(*k)*kernel_pixels->red;
+            pixel.green+=(*k)*kernel_pixels->green;
+            pixel.blue+=(*k)*kernel_pixels->blue;
+            k++;
+            kernel_pixels++;
+          }
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.opacity+=(*k)*kernel_pixels->opacity;
+                k++;
+                kernel_pixels++;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=kernel;
+              kernel_indexes=indexes;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.index+=(*k)*(*kernel_indexes);
+                k++;
+                kernel_indexes++;
+              }
+              blur_indexes[y]=RoundToQuantum(pixel.index+bias);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < (long) width; i++)
+          {
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+              kernel_pixels->opacity));
+            pixel.red+=(*k)*alpha*kernel_pixels->red;
+            pixel.green+=(*k)*alpha*kernel_pixels->green;
+            pixel.blue+=(*k)*alpha*kernel_pixels->blue;
+            gamma+=(*k)*alpha;
+            k++;
+            kernel_pixels++;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(gamma*pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(gamma*pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (long) width; i++)
+              {
+                pixel.opacity+=(*k)*kernel_pixels->opacity;
+                k++;
+                kernel_pixels++;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=kernel;
+              kernel_pixels=p;
+              kernel_indexes=indexes;
+              for (i=0; i < (long) width; i++)
+              {
+                alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                  kernel_pixels->opacity));
+                pixel.index+=(*k)*alpha*(*kernel_indexes);
+                k++;
+                kernel_pixels++;
+                kernel_indexes++;
+              }
+              blur_indexes[y]=RoundToQuantum(gamma*pixel.index+bias);
+            }
+        }
+      p++;
+      q++;
+    }
+    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);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  blur_image->type=image->type;
+  return(blur_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 Quantum **DestroyPixelThreadSet(Quantum **pixels)
+{
+  register long
+    i;
+
+  assert(pixels != (Quantum **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (Quantum *) NULL)
+      pixels[i]=(Quantum *) RelinquishMagickMemory(pixels[i]);
+  pixels=(Quantum **) RelinquishAlignedMemory(pixels);
+  return(pixels);
+}
+
+static Quantum **AcquirePixelThreadSet(const size_t count)
+{
+  register long
+    i;
+
+  Quantum
+    **pixels;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(Quantum **) AcquireAlignedMemory(number_threads,sizeof(*pixels));
+  if (pixels == (Quantum **) NULL)
+    return((Quantum **) NULL);
+  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+  for (i=0; i < (long) number_threads; i++)
+  {
+    pixels[i]=(Quantum *) AcquireQuantumMemory(count,sizeof(**pixels));
+    if (pixels[i] == (Quantum *) NULL)
+      return(DestroyPixelThreadSet(pixels));
+  }
+  return(pixels);
+}
+
+static void Hull(const long x_offset,const long y_offset,
+  const unsigned long columns,const unsigned long rows,Quantum *f,Quantum *g,
+  const int polarity)
+{
+  long
+    y;
+
+  MagickRealType
+    v;
+
+  register long
+    x;
+
+  register Quantum
+    *p,
+    *q,
+    *r,
+    *s;
+
+  assert(f != (Quantum *) NULL);
+  assert(g != (Quantum *) NULL);
+  p=f+(columns+2);
+  q=g+(columns+2);
+  r=p+(y_offset*((long) columns+2)+x_offset);
+  for (y=0; y < (long) rows; y++)
+  {
+    p++;
+    q++;
+    r++;
+    if (polarity > 0)
+      for (x=(long) 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=(long) columns; x != 0; x--)
+      {
+        v=(MagickRealType) (*p);
+        if ((MagickRealType) *r <= (v-(MagickRealType) ScaleCharToQuantum(2)))
+          v-=(long) ScaleCharToQuantum(1);
+        *q=(Quantum) v;
+        p++;
+        q++;
+        r++;
+      }
+    p++;
+    q++;
+    r++;
+  }
+  p=f+(columns+2);
+  q=g+(columns+2);
+  r=q+(y_offset*((long) columns+2)+x_offset);
+  s=q-(y_offset*((long) columns+2)+x_offset);
+  for (y=0; y < (long) rows; y++)
+  {
+    p++;
+    q++;
+    r++;
+    s++;
+    if (polarity > 0)
+      for (x=(long) 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=(long) 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"
+
+  Image
+    *despeckle_image;
+
+  long
+    channel;
+
+  MagickBooleanType
+    status;
+
+  Quantum
+    **buffers,
+    **pixels;
+
+  size_t
+    length;
+
+  static const int
+    X[4]= {0, 1, 1,-1},
+    Y[4]= {1, 0, 1, 1};
+
+  CacheView
+    *despeckle_view,
+    *image_view;
+
+  /*
+    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=AcquirePixelThreadSet(length);
+  buffers=AcquirePixelThreadSet(length);
+  if ((pixels == (Quantum **) NULL) || (buffers == (Quantum **) NULL))
+    {
+      if (buffers != (Quantum **) NULL)
+        buffers=DestroyPixelThreadSet(buffers);
+      if (pixels != (Quantum **) NULL)
+        pixels=DestroyPixelThreadSet(pixels);
+      despeckle_image=DestroyImage(despeckle_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Reduce speckle in the image.
+  */
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  despeckle_view=AcquireCacheView(despeckle_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,1) shared(status)
+#endif
+  for (channel=0; channel <= 3; channel++)
+  {
+    long
+      j,
+      y;
+
+    register long
+      i,
+      x;
+
+    register Quantum
+      *buffer,
+      *pixel;
+
+    if (status == MagickFalse)
+      continue;
+    pixel=pixels[GetOpenMPThreadId()];
+    (void) ResetMagickMemory(pixel,0,length*sizeof(*pixel));
+    j=(long) image->columns+2;
+    for (y=0; y < (long) image->rows; y++)
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      j++;
+      for (x=0; x < (long) image->columns; x++)
+      {
+        switch (channel)
+        {
+          case 0: pixel[j]=p->red; break;
+          case 1: pixel[j]=p->green; break;
+          case 2: pixel[j]=p->blue; break;
+          case 3: pixel[j]=p->opacity; break;
+          default: break;
+        }
+        p++;
+        j++;
+      }
+      j++;
+    }
+    buffer=buffers[GetOpenMPThreadId()];
+    (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
+    for (i=0; i < 4; i++)
+    {
+      Hull(X[i],Y[i],image->columns,image->rows,pixel,buffer,1);
+      Hull(-X[i],-Y[i],image->columns,image->rows,pixel,buffer,1);
+      Hull(-X[i],-Y[i],image->columns,image->rows,pixel,buffer,-1);
+      Hull(X[i],Y[i],image->columns,image->rows,pixel,buffer,-1);
+    }
+    j=(long) image->columns+2;
+    for (y=0; y < (long) image->rows; y++)
+    {
+      MagickBooleanType
+        sync;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
+        1,exception);
+      if (q == (PixelPacket *) NULL)
+        break;
+      j++;
+      for (x=0; x < (long) image->columns; x++)
+      {
+        switch (channel)
+        {
+          case 0: q->red=pixel[j]; break;
+          case 1: q->green=pixel[j]; break;
+          case 2: q->blue=pixel[j]; break;
+          case 3: q->opacity=pixel[j]; break;
+          default: break;
+        }
+        q++;
+        j++;
+      }
+      sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
+      if (sync == MagickFalse)
+        {
+          status=MagickFalse;
+          break;
+        }
+      j++;
+    }
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_DespeckleImage)
+#endif
+        proceed=SetImageProgress(image,DespeckleImageTag,channel,3);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  despeckle_view=DestroyCacheView(despeckle_view);
+  image_view=DestroyCacheView(image_view);
+  buffers=DestroyPixelThreadSet(buffers);
+  pixels=DestroyPixelThreadSet(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 long
+    i;
+
+  unsigned long
+    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 < (long) (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;
+
+  long
+    j;
+
+  MagickRealType
+    alpha;
+
+  register long
+    i,
+    u,
+    v;
+
+  unsigned long
+    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);
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  i=0;
+  j=(long) width/2;
+  for (v=(-((long) width/2)); v <= (long) (width/2); v++)
+  {
+    for (u=(-((long) width/2)); u <= (long) (width/2); u++)
+    {
+      alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+      kernel[i]=(double) (((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
+        (2.0*MagickPI*MagickSigma*MagickSigma));
+      if (u != j)
+        kernel[i]=0.0;
+      i++;
+    }
+    j--;
+  }
+  emboss_image=ConvolveImage(image,width,kernel,exception);
+  if (emboss_image != (Image *) NULL)
+    (void) EqualizeImage(emboss_image);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(emboss_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;
+
+  MagickRealType
+    alpha;
+
+  register long
+    i,
+    u,
+    v;
+
+  unsigned long
+    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=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  i=0;
+  for (v=(-((long) width/2)); v <= (long) (width/2); v++)
+  {
+    for (u=(-((long) width/2)); u <= (long) (width/2); u++)
+    {
+      alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+      kernel[i]=(double) (alpha/(2.0*MagickPI*MagickSigma*MagickSigma));
+      i++;
+    }
+  }
+  blur_image=ConvolveImageChannel(image,channel,width,kernel,exception);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M e d i a n F i l t e r I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MedianFilterImage() applies a digital filter that improves the quality
+%  of a noisy image.  Each pixel is replaced by the median in a set of
+%  neighboring pixels as defined by radius.
+%
+%  The algorithm was contributed by Mike Edmonds and implements an insertion
+%  sort for selecting median color-channel values.  For more on this algorithm
+%  see "Skip Lists: A probabilistic Alternative to Balanced Trees" by William
+%  Pugh in the June 1990 of Communications of the ACM.
+%
+%  The format of the MedianFilterImage method is:
+%
+%      Image *MedianFilterImage(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.
+%
+*/
+
+#define MedianListChannels  5
+
+typedef struct _MedianListNode
+{
+  unsigned long
+    next[9],
+    count,
+    signature;
+} MedianListNode;
+
+typedef struct _MedianSkipList
+{
+  long
+    level;
+
+  MedianListNode
+    *nodes;
+} MedianSkipList;
+
+typedef struct _MedianPixelList
+{
+  unsigned long
+    center,
+    seed,
+    signature;
+
+  MedianSkipList
+    lists[MedianListChannels];
+} MedianPixelList;
+
+static MedianPixelList *DestroyMedianPixelList(MedianPixelList *pixel_list)
+{
+  register long
+    i;
+
+  if (pixel_list == (MedianPixelList *) NULL)
+    return((MedianPixelList *) NULL);
+  for (i=0; i < MedianListChannels; i++)
+    if (pixel_list->lists[i].nodes != (MedianListNode *) NULL)
+      pixel_list->lists[i].nodes=(MedianListNode *) RelinquishMagickMemory(
+        pixel_list->lists[i].nodes);
+  pixel_list=(MedianPixelList *) RelinquishAlignedMemory(pixel_list);
+  return(pixel_list);
+}
+
+static MedianPixelList **DestroyMedianPixelListThreadSet(
+  MedianPixelList **pixel_list)
+{
+  register long
+    i;
+
+  assert(pixel_list != (MedianPixelList **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (pixel_list[i] != (MedianPixelList *) NULL)
+      pixel_list[i]=DestroyMedianPixelList(pixel_list[i]);
+  pixel_list=(MedianPixelList **) RelinquishAlignedMemory(pixel_list);
+  return(pixel_list);
+}
+
+static MedianPixelList *AcquireMedianPixelList(const unsigned long width)
+{
+  MedianPixelList
+    *pixel_list;
+
+  register long
+    i;
+
+  pixel_list=(MedianPixelList *) AcquireAlignedMemory(1,sizeof(*pixel_list));
+  if (pixel_list == (MedianPixelList *) NULL)
+    return(pixel_list);
+  (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
+  pixel_list->center=width*width/2;
+  for (i=0; i < MedianListChannels; i++)
+  {
+    pixel_list->lists[i].nodes=(MedianListNode *) AcquireQuantumMemory(65537UL,
+      sizeof(*pixel_list->lists[i].nodes));
+    if (pixel_list->lists[i].nodes == (MedianListNode *) NULL)
+      return(DestroyMedianPixelList(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 MedianPixelList **AcquireMedianPixelListThreadSet(
+  const unsigned long width)
+{
+  register long
+    i;
+
+  MedianPixelList
+    **pixel_list;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixel_list=(MedianPixelList **) AcquireAlignedMemory(number_threads,
+    sizeof(*pixel_list));
+  if (pixel_list == (MedianPixelList **) NULL)
+    return((MedianPixelList **) NULL);
+  (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
+  for (i=0; i < (long) number_threads; i++)
+  {
+    pixel_list[i]=AcquireMedianPixelList(width);
+    if (pixel_list[i] == (MedianPixelList *) NULL)
+      return(DestroyMedianPixelListThreadSet(pixel_list));
+  }
+  return(pixel_list);
+}
+
+static void AddNodeMedianPixelList(MedianPixelList *pixel_list,
+  const long channel,const unsigned long color)
+{
+  register long
+    level;
+
+  register MedianSkipList
+    *list;
+
+  unsigned long
+    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 MagickPixelPacket GetMedianPixelList(MedianPixelList *pixel_list)
+{
+  MagickPixelPacket
+    pixel;
+
+  register long
+    channel;
+
+  register MedianSkipList
+    *list;
+
+  unsigned long
+    center,
+    color,
+    count;
+
+  unsigned short
+    channels[MedianListChannels];
+
+  /*
+    Find the median value for each of the color.
+  */
+  center=pixel_list->center;
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536UL;
+    count=0;
+    do
+    {
+      color=list->nodes[color].next[0];
+      count+=list->nodes[color].count;
+    }
+    while (count <= center);
+    channels[channel]=(unsigned short) color;
+  }
+  GetMagickPixelPacket((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  return(pixel);
+}
+
+static inline void InsertMedianPixelList(const Image *image,
+  const PixelPacket *pixel,const IndexPacket *indexes,
+  MedianPixelList *pixel_list)
+{
+  unsigned long
+    signature;
+
+  unsigned short
+    index;
+
+  index=ScaleQuantumToShort(pixel->red);
+  signature=pixel_list->lists[0].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[0].nodes[index].count++;
+  else
+    AddNodeMedianPixelList(pixel_list,0,index);
+  index=ScaleQuantumToShort(pixel->green);
+  signature=pixel_list->lists[1].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[1].nodes[index].count++;
+  else
+    AddNodeMedianPixelList(pixel_list,1,index);
+  index=ScaleQuantumToShort(pixel->blue);
+  signature=pixel_list->lists[2].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[2].nodes[index].count++;
+  else
+    AddNodeMedianPixelList(pixel_list,2,index);
+  index=ScaleQuantumToShort(pixel->opacity);
+  signature=pixel_list->lists[3].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[3].nodes[index].count++;
+  else
+    AddNodeMedianPixelList(pixel_list,3,index);
+  if (image->colorspace == CMYKColorspace)
+    index=ScaleQuantumToShort(*indexes);
+  signature=pixel_list->lists[4].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[4].nodes[index].count++;
+  else
+    AddNodeMedianPixelList(pixel_list,4,index);
+}
+
+static void ResetMedianPixelList(MedianPixelList *pixel_list)
+{
+  int
+    level;
+
+  register long
+    channel;
+
+  register MedianListNode
+    *root;
+
+  register MedianSkipList
+    *list;
+
+  /*
+    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 *MedianFilterImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+#define MedianFilterImageTag  "MedianFilter/Image"
+
+  Image
+    *median_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MedianPixelList
+    **pixel_list;
+
+  unsigned long
+    width;
+
+  CacheView
+    *image_view,
+    *median_view;
+
+  /*
+    Initialize median 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=GetOptimalKernelWidth2D(radius,0.5);
+  if ((image->columns < width) || (image->rows < width))
+    ThrowImageException(OptionError,"ImageSmallerThanKernelRadius");
+  median_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (median_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(median_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&median_image->exception);
+      median_image=DestroyImage(median_image);
+      return((Image *) NULL);
+    }
+  pixel_list=AcquireMedianPixelListThreadSet(width);
+  if (pixel_list == (MedianPixelList **) NULL)
+    {
+      median_image=DestroyImage(median_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Median filter each image row.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  median_view=AcquireCacheView(median_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) median_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict median_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
+      2L),image->columns+width,width,exception);
+    q=QueueCacheViewAuthenticPixels(median_view,0,y,median_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    median_indexes=GetCacheViewAuthenticIndexQueue(median_view);
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) median_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      register const PixelPacket
+        *__restrict r;
+
+      register const IndexPacket
+        *__restrict s;
+
+      register long
+        u,
+        v;
+
+      r=p;
+      s=indexes+x;
+      ResetMedianPixelList(pixel_list[id]);
+      for (v=0; v < (long) width; v++)
+      {
+        for (u=0; u < (long) width; u++)
+          InsertMedianPixelList(image,r+u,s+u,pixel_list[id]);
+        r+=image->columns+width;
+        s+=image->columns+width;
+      }
+      pixel=GetMedianPixelList(pixel_list[id]);
+      SetPixelPacket(median_image,&pixel,q,median_indexes+x);
+      p++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(median_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_MedianFilterImage)
+#endif
+        proceed=SetImageProgress(image,MedianFilterImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  median_view=DestroyCacheView(median_view);
+  image_view=DestroyCacheView(image_view);
+  pixel_list=DestroyMedianPixelListThreadSet(pixel_list);
+  return(median_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(unsigned long width,
+  const MagickRealType sigma)
+{
+#define KernelRank 3
+
+  double
+    *kernel;
+
+  long
+    bias;
+
+  MagickRealType
+    alpha,
+    normalize;
+
+  register long
+    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);
+  (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
+  bias=(long) (KernelRank*width);
+  for (i=0; i < (long) bias; i++)
+  {
+    alpha=exp((-((double) (i*i))/(double) (2.0*KernelRank*KernelRank*
+      MagickSigma*MagickSigma)));
+    kernel[i/KernelRank]+=(double) alpha/(MagickSQ2PI*sigma);
+  }
+  normalize=0.0;
+  for (i=0; i < (long) width; i++)
+    normalize+=kernel[i];
+  for (i=0; i < (long) 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)
+{
+  typedef struct _OffsetInfo
+  {
+    long
+      x,
+      y;
+  } OffsetInfo;
+
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  OffsetInfo
+    *offset;
+
+  PointInfo
+    point;
+
+  register long
+    i;
+
+  unsigned long
+    width;
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  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 < (long) width; i++)
+  {
+    offset[i].x=(long) ((i*point.y)/hypot(point.x,point.y)+0.5);
+    offset[i].y=(long) ((i*point.x)/hypot(point.x,point.y)+0.5);
+  }
+  /*
+    Motion blur image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(image,&zero);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickPixelPacket
+        qixel;
+
+      PixelPacket
+        pixel;
+
+      register double
+        *__restrict k;
+
+      register long
+        i;
+
+      register const IndexPacket
+        *__restrict indexes;
+
+      k=kernel;
+      qixel=zero;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (long) 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.opacity+=(*k)*pixel.opacity;
+            if (image->colorspace == CMYKColorspace)
+              {
+                indexes=GetCacheViewVirtualIndexQueue(image_view);
+                qixel.index+=(*k)*(*indexes);
+              }
+            k++;
+          }
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(qixel.red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(qixel.green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(qixel.blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(qixel.opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            blur_indexes[x]=(IndexPacket) RoundToQuantum(qixel.index);
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          alpha=0.0;
+          gamma=0.0;
+          for (i=0; i < (long) width; i++)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
+              offset[i].y,&pixel,exception);
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-pixel.opacity));
+            qixel.red+=(*k)*alpha*pixel.red;
+            qixel.green+=(*k)*alpha*pixel.green;
+            qixel.blue+=(*k)*alpha*pixel.blue;
+            qixel.opacity+=(*k)*pixel.opacity;
+            if (image->colorspace == CMYKColorspace)
+              {
+                indexes=GetCacheViewVirtualIndexQueue(image_view);
+                qixel.index+=(*k)*alpha*(*indexes);
+              }
+            gamma+=(*k)*alpha;
+            k++;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(gamma*qixel.red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(gamma*qixel.green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(gamma*qixel.blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(qixel.opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            blur_indexes[x]=(IndexPacket) RoundToQuantum(gamma*qixel.index);
+        }
+      q++;
+    }
+    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;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  MontageInfo
+    *montage_info;
+
+  QuantizeInfo
+    quantize_info;
+
+  RectangleInfo
+    geometry;
+
+  register long
+    i,
+    x;
+
+  unsigned long
+    colors;
+
+  /*
+    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) FormatMagickString(label,MaxTextExtent,"rotate %g",degrees);
+        break;
+      }
+      case ShearPreview:
+      {
+        degrees+=5.0;
+        preview_image=ShearImage(thumbnail,degrees,degrees,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"shear %gx%g",
+          degrees,2.0*degrees);
+        break;
+      }
+      case RollPreview:
+      {
+        x=(long) ((i+1)*thumbnail->columns)/NumberTiles;
+        y=(long) ((i+1)*thumbnail->rows)/NumberTiles;
+        preview_image=RollImage(thumbnail,x,y,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"roll %ldx%ld",x,y);
+        break;
+      }
+      case HuePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatMagickString(factor,MaxTextExtent,"100,100,%g",
+          2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatMagickString(label,MaxTextExtent,"modulate %s",factor);
+        break;
+      }
+      case SaturationPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatMagickString(factor,MaxTextExtent,"100,%g",2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatMagickString(label,MaxTextExtent,"modulate %s",factor);
+        break;
+      }
+      case BrightnessPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatMagickString(factor,MaxTextExtent,"%g",2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatMagickString(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) FormatMagickString(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) FormatMagickString(label,MaxTextExtent,"contrast (%ld)",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) FormatMagickString(label,MaxTextExtent,"+contrast (%ld)",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) FormatMagickString(label,MaxTextExtent,
+          "-colorspace gray -colors %ld",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) FormatMagickString(label,MaxTextExtent,"colors %ld",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) FormatMagickString(label,MaxTextExtent,"despeckle (%ld)",i+1);
+        break;
+      }
+      case ReduceNoisePreview:
+      {
+        preview_image=ReduceNoiseImage(thumbnail,radius,exception);
+        (void) FormatMagickString(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=ReduceNoiseImage(thumbnail,(double) i,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"+noise %s",factor);
+        break;
+      }
+      case SharpenPreview:
+      {
+        preview_image=SharpenImage(thumbnail,radius,sigma,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"sharpen %gx%g",radius,
+          sigma);
+        break;
+      }
+      case BlurPreview:
+      {
+        preview_image=BlurImage(thumbnail,radius,sigma,exception);
+        (void) FormatMagickString(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) FormatMagickString(label,MaxTextExtent,"threshold %g",
+          (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
+        break;
+      }
+      case EdgeDetectPreview:
+      {
+        preview_image=EdgeImage(thumbnail,radius,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"edge %g",radius);
+        break;
+      }
+      case SpreadPreview:
+      {
+        preview_image=SpreadImage(thumbnail,radius,exception);
+        (void) FormatMagickString(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) FormatMagickString(label,MaxTextExtent,"solarize %g",
+          (QuantumRange*percentage)/100.0);
+        break;
+      }
+      case ShadePreview:
+      {
+        degrees+=10.0;
+        preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
+          exception);
+        (void) FormatMagickString(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=(unsigned long) (2*i+2);
+        geometry.height=(unsigned long) (2*i+2);
+        geometry.x=i/2;
+        geometry.y=i/2;
+        (void) RaiseImage(preview_image,&geometry,MagickTrue);
+        (void) FormatMagickString(label,MaxTextExtent,"raise %lux%lu%+ld%+ld",
+          geometry.width,geometry.height,geometry.x,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) FormatMagickString(label,MaxTextExtent,"segment %gx%g",
+          threshold,threshold);
+        break;
+      }
+      case SwirlPreview:
+      {
+        preview_image=SwirlImage(thumbnail,degrees,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"swirl %g",degrees);
+        degrees+=45.0;
+        break;
+      }
+      case ImplodePreview:
+      {
+        degrees+=0.1f;
+        preview_image=ImplodeImage(thumbnail,degrees,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"implode %g",degrees);
+        break;
+      }
+      case WavePreview:
+      {
+        degrees+=5.0f;
+        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"wave %gx%g",0.5*degrees,
+          2.0*degrees);
+        break;
+      }
+      case OilPaintPreview:
+      {
+        preview_image=OilPaintImage(thumbnail,(double) radius,exception);
+        (void) FormatMagickString(label,MaxTextExtent,"paint %g",radius);
+        break;
+      }
+      case CharcoalDrawingPreview:
+      {
+        preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
+          exception);
+        (void) FormatMagickString(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=(unsigned long) percentage;
+        (void) FormatMagickString(factor,MaxTextExtent,"%lu",
+          preview_info->quality);
+        file=AcquireUniqueFileResource(filename);
+        if (file != -1)
+          file=close(file)-1;
+        (void) FormatMagickString(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) FormatMagickString(label,MaxTextExtent,"quality %s\n%gmb ",
+            factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
+            1024.0/1024.0);
+        else
+          if (GetBlobSize(preview_image) >= 1024)
+            (void) FormatMagickString(label,MaxTextExtent,"quality %s\n%gkb ",
+              factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
+              1024.0);
+          else
+            (void) FormatMagickString(label,MaxTextExtent,"quality %s\n%lub ",
+              factor,(unsigned long) 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,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)
+{
+  Image
+    *blur_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    blur_radius,
+    *cos_theta,
+    offset,
+    *sin_theta,
+    theta;
+
+  PointInfo
+    blur_center;
+
+  register long
+    i;
+
+  unsigned long
+    n;
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  /*
+    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=(unsigned long) 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 < (long) 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;
+  GetMagickPixelPacket(image,&zero);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) blur_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (x=0; x < (long) blur_image->columns; x++)
+    {
+      MagickPixelPacket
+        qixel;
+
+      MagickRealType
+        normalize,
+        radius;
+
+      PixelPacket
+        pixel;
+
+      PointInfo
+        center;
+
+      register long
+        i;
+
+      unsigned long
+        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=(unsigned long) (blur_radius/radius);
+          if (step == 0)
+            step=1;
+          else
+            if (step >= n)
+              step=n-1;
+        }
+      normalize=0.0;
+      qixel=zero;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (long) n; i+=step)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,(long) (blur_center.x+
+              center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),(long) (
+              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;
+            qixel.opacity+=pixel.opacity;
+            if (image->colorspace == CMYKColorspace)
+              {
+                indexes=GetCacheViewVirtualIndexQueue(image_view);
+                qixel.index+=(*indexes);
+              }
+            normalize+=1.0;
+          }
+          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
+            normalize);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(normalize*qixel.red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(normalize*qixel.green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(normalize*qixel.blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(normalize*qixel.opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            blur_indexes[x]=(IndexPacket) RoundToQuantum(normalize*qixel.index);
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          alpha=1.0;
+          gamma=0.0;
+          for (i=0; i < (long) n; i+=step)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,(long) (blur_center.x+
+              center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),(long) (
+              blur_center.y+center.x*sin_theta[i]+center.y*cos_theta[i]+0.5),
+              &pixel,exception);
+            alpha=(MagickRealType) (QuantumScale*(QuantumRange-pixel.opacity));
+            qixel.red+=alpha*pixel.red;
+            qixel.green+=alpha*pixel.green;
+            qixel.blue+=alpha*pixel.blue;
+            qixel.opacity+=pixel.opacity;
+            if (image->colorspace == CMYKColorspace)
+              {
+                indexes=GetCacheViewVirtualIndexQueue(image_view);
+                qixel.index+=alpha*(*indexes);
+              }
+            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)
+            q->red=RoundToQuantum(gamma*qixel.red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(gamma*qixel.green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(gamma*qixel.blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(normalize*qixel.opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            blur_indexes[x]=(IndexPacket) RoundToQuantum(gamma*qixel.index);
+        }
+      q++;
+    }
+    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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R e d u c e N o i s e I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReduceNoiseImage() smooths the contours of an image while still preserving
+%  edge information.  The algorithm works by replacing each pixel with its
+%  neighbor closest in value.  A neighbor is defined by radius.  Use a radius
+%  of 0 and ReduceNoise() selects a suitable radius for you.
+%
+%  The format of the ReduceNoiseImage method is:
+%
+%      Image *ReduceNoiseImage(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.
+%
+*/
+
+static MagickPixelPacket GetNonpeakMedianPixelList(MedianPixelList *pixel_list)
+{
+  MagickPixelPacket
+    pixel;
+
+  register long
+    channel;
+
+  register MedianSkipList
+    *list;
+
+  unsigned long
+    center,
+    color,
+    count,
+    previous,
+    next;
+
+  unsigned short
+    channels[5];
+
+  /*
+    Finds the median value for each of the color.
+  */
+  center=pixel_list->center;
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536UL;
+    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 <= center);
+    if ((previous == 65536UL) && (next != 65536UL))
+      color=next;
+    else
+      if ((previous != 65536UL) && (next == 65536UL))
+        color=previous;
+    channels[channel]=(unsigned short) color;
+  }
+  GetMagickPixelPacket((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  pixel.index=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  return(pixel);
+}
+
+MagickExport Image *ReduceNoiseImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+#define ReduceNoiseImageTag  "ReduceNoise/Image"
+
+  Image
+    *noise_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MedianPixelList
+    **pixel_list;
+
+  unsigned long
+    width;
+
+  CacheView
+    *image_view,
+    *noise_view;
+
+  /*
+    Initialize noise 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=GetOptimalKernelWidth2D(radius,0.5);
+  if ((image->columns < width) || (image->rows < width))
+    ThrowImageException(OptionError,"ImageSmallerThanKernelRadius");
+  noise_image=CloneImage(image,image->columns,image->rows,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);
+    }
+  pixel_list=AcquireMedianPixelListThreadSet(width);
+  if (pixel_list == (MedianPixelList **) NULL)
+    {
+      noise_image=DestroyImage(noise_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Reduce noise image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  noise_view=AcquireCacheView(noise_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) noise_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict noise_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
+      2L),image->columns+width,width,exception);
+    q=QueueCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) noise_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      register const PixelPacket
+        *__restrict r;
+
+      register const IndexPacket
+        *__restrict s;
+
+      register long
+        u,
+        v;
+
+      r=p;
+      s=indexes+x;
+      ResetMedianPixelList(pixel_list[id]);
+      for (v=0; v < (long) width; v++)
+      {
+        for (u=0; u < (long) width; u++)
+          InsertMedianPixelList(image,r+u,s+u,pixel_list[id]);
+        r+=image->columns+width;
+        s+=image->columns+width;
+      }
+      pixel=GetNonpeakMedianPixelList(pixel_list[id]);
+      SetPixelPacket(noise_image,&pixel,q,noise_indexes+x);
+      p++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(noise_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ReduceNoiseImage)
+#endif
+        proceed=SetImageProgress(image,ReduceNoiseImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  noise_view=DestroyCacheView(noise_view);
+  image_view=DestroyCacheView(image_view);
+  pixel_list=DestroyMedianPixelListThreadSet(pixel_list);
+  return(noise_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.
+%
+*/
+
+static inline MagickBooleanType SelectiveContrast(const PixelPacket *p,
+  const PixelPacket *q,const double threshold)
+{
+  if (fabs(PixelIntensity(p)-PixelIntensity(q)) < threshold)
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+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"
+
+  double
+    alpha,
+    *kernel;
+
+  Image
+    *blur_image;
+
+  long
+    progress,
+    v,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    bias;
+
+  register long
+    i,
+    u;
+
+  unsigned long
+    width;
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  /*
+    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");
+  i=0;
+  for (v=(-((long) width/2)); v <= (long) (width/2); v++)
+  {
+    for (u=(-((long) width/2)); u <= (long) (width/2); u++)
+    {
+      alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+      kernel[i]=(double) (alpha/(2.0*MagickPI*MagickSigma*MagickSigma));
+      i++;
+    }
+  }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      long
+        u,
+        v;
+
+      register const double
+        *k;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  SelectiveBlurImage with %ldx%ld kernel:",width,width);
+      message=AcquireString("");
+      k=kernel;
+      for (v=0; v < (long) width; v++)
+      {
+        *message='\0';
+        (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (long) width; u++)
+        {
+          (void) FormatMagickString(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;
+  GetMagickPixelPacket(image,&zero);
+  bias=image->bias;
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    MagickRealType
+      gamma;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict blur_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
+      2L),image->columns+width,width,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      long
+        j,
+        v;
+
+      MagickPixelPacket
+        pixel;
+
+      register const double
+        *__restrict k;
+
+      register long
+        u;
+
+      pixel=zero;
+      k=kernel;
+      gamma=0.0;
+      j=0;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (v=0; v < (long) width; v++)
+          {
+            for (u=0; u < (long) width; u++)
+            {
+              if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                {
+                  pixel.red+=(*k)*(p+u+j)->red;
+                  pixel.green+=(*k)*(p+u+j)->green;
+                  pixel.blue+=(*k)*(p+u+j)->blue;
+                  gamma+=(*k);
+                  k++;
+                }
+            }
+            j+=image->columns+width;
+          }
+          if (gamma != 0.0)
+            {
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              if ((channel & RedChannel) != 0)
+                q->red=RoundToQuantum(gamma*pixel.red+bias);
+              if ((channel & GreenChannel) != 0)
+                q->green=RoundToQuantum(gamma*pixel.green+bias);
+              if ((channel & BlueChannel) != 0)
+                q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+            }
+          if ((channel & OpacityChannel) != 0)
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                    {
+                      pixel.opacity+=(*k)*(p+u+j)->opacity;
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=image->columns+width;
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  q->opacity=RoundToQuantum(gamma*pixel.opacity+bias);
+                }
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                    {
+                      pixel.index+=(*k)*indexes[x+u+j];
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=image->columns+width;
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  blur_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+                }
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha;
+
+          for (v=0; v < (long) width; v++)
+          {
+            for (u=0; u < (long) width; u++)
+            {
+              if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                {
+                  alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                    (p+u+j)->opacity));
+                  pixel.red+=(*k)*alpha*(p+u+j)->red;
+                  pixel.green+=(*k)*alpha*(p+u+j)->green;
+                  pixel.blue+=(*k)*alpha*(p+u+j)->blue;
+                  pixel.opacity+=(*k)*(p+u+j)->opacity;
+                  gamma+=(*k)*alpha;
+                  k++;
+                }
+            }
+            j+=image->columns+width;
+          }
+          if (gamma != 0.0)
+            {
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              if ((channel & RedChannel) != 0)
+                q->red=RoundToQuantum(gamma*pixel.red+bias);
+              if ((channel & GreenChannel) != 0)
+                q->green=RoundToQuantum(gamma*pixel.green+bias);
+              if ((channel & BlueChannel) != 0)
+                q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+            }
+          if ((channel & OpacityChannel) != 0)
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                    {
+                      pixel.opacity+=(*k)*(p+u+j)->opacity;
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=image->columns+width;
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  q->opacity=RoundToQuantum(pixel.opacity+bias);
+                }
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  if (SelectiveContrast(p+u+j,q,threshold) != MagickFalse)
+                    {
+                      alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                        (p+u+j)->opacity));
+                      pixel.index+=(*k)*alpha*indexes[x+u+j];
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=image->columns+width;
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  blur_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+                }
+            }
+        }
+      p++;
+      q++;
+    }
+    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"
+
+  Image
+    *shade_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  PrimaryInfo
+    light;
+
+  CacheView
+    *image_view,
+    *shade_view;
+
+  /*
+    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) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickRealType
+      distance,
+      normal_distance,
+      shade;
+
+    PrimaryInfo
+      normal;
+
+    register const PixelPacket
+      *__restrict p,
+      *__restrict s0,
+      *__restrict s1,
+      *__restrict s2;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    /*
+      Shade this row of pixels.
+    */
+    normal.z=2.0*(double) QuantumRange;  /* constant Z of surface normal */
+    s0=p+1;
+    s1=s0+image->columns+2;
+    s2=s1+image->columns+2;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      /*
+        Determine the surface normal and compute shading.
+      */
+      normal.x=(double) (PixelIntensity(s0-1)+PixelIntensity(s1-1)+
+        PixelIntensity(s2-1)-PixelIntensity(s0+1)-PixelIntensity(s1+1)-
+        PixelIntensity(s2+1));
+      normal.y=(double) (PixelIntensity(s2-1)+PixelIntensity(s2)+
+        PixelIntensity(s2+1)-PixelIntensity(s0-1)-PixelIntensity(s0)-
+        PixelIntensity(s0+1));
+      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)
+        {
+          q->red=(Quantum) shade;
+          q->green=(Quantum) shade;
+          q->blue=(Quantum) shade;
+        }
+      else
+        {
+          q->red=RoundToQuantum(QuantumScale*shade*s1->red);
+          q->green=RoundToQuantum(QuantumScale*shade*s1->green);
+          q->blue=RoundToQuantum(QuantumScale*shade*s1->blue);
+        }
+      q->opacity=s1->opacity;
+      s0++;
+      s1++;
+      s2++;
+      q++;
+    }
+    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;
+
+  Image
+    *sharp_image;
+
+  MagickRealType
+    alpha,
+    normalize;
+
+  register long
+    i,
+    u,
+    v;
+
+  unsigned long
+    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=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width*width,sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  i=0;
+  normalize=0.0;
+  for (v=(-((long) width/2)); v <= (long) (width/2); v++)
+  {
+    for (u=(-((long) width/2)); u <= (long) (width/2); u++)
+    {
+      alpha=exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma));
+      kernel[i]=(double) (-alpha/(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"
+
+  Image
+    *spread_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  RandomInfo
+    **random_info;
+
+  ResampleFilter
+    **resample_filter;
+
+  unsigned long
+    width;
+
+  CacheView
+    *image_view;
+
+  /*
+    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;
+  GetMagickPixelPacket(spread_image,&zero);
+  width=GetOptimalKernelWidth1D(radius,0.5);
+  resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(spread_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) spread_image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,spread_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) spread_image->columns; x++)
+    {
+      (void) ResamplePixelColor(resample_filter[id],(double) x+width*
+        (GetPseudoRandomValue(random_info[id])-0.5),(double) y+width*
+        (GetPseudoRandomValue(random_info[id])-0.5),&pixel);
+      SetPixelPacket(spread_image,&pixel,q,indexes+x);
+      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_SpreadImage)
+#endif
+        proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  return(spread_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"
+
+  Image
+    *unsharp_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    quantum_threshold;
+
+  CacheView
+    *image_view,
+    *unsharp_view;
+
+  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;
+  GetMagickPixelPacket(image,&zero);
+  image_view=AcquireCacheView(image);
+  unsharp_view=AcquireCacheView(unsharp_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict unsharp_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    unsharp_indexes=GetCacheViewAuthenticIndexQueue(unsharp_view);
+    pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          pixel.red=p->red-(MagickRealType) q->red;
+          if (fabs(2.0*pixel.red) < quantum_threshold)
+            pixel.red=(MagickRealType) p->red;
+          else
+            pixel.red=(MagickRealType) p->red+(pixel.red*amount);
+          q->red=RoundToQuantum(pixel.red);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          pixel.green=p->green-(MagickRealType) q->green;
+          if (fabs(2.0*pixel.green) < quantum_threshold)
+            pixel.green=(MagickRealType) p->green;
+          else
+            pixel.green=(MagickRealType) p->green+(pixel.green*amount);
+          q->green=RoundToQuantum(pixel.green);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          pixel.blue=p->blue-(MagickRealType) q->blue;
+          if (fabs(2.0*pixel.blue) < quantum_threshold)
+            pixel.blue=(MagickRealType) p->blue;
+          else
+            pixel.blue=(MagickRealType) p->blue+(pixel.blue*amount);
+          q->blue=RoundToQuantum(pixel.blue);
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          pixel.opacity=p->opacity-(MagickRealType) q->opacity;
+          if (fabs(2.0*pixel.opacity) < quantum_threshold)
+            pixel.opacity=(MagickRealType) p->opacity;
+          else
+            pixel.opacity=p->opacity+(pixel.opacity*amount);
+          q->opacity=RoundToQuantum(pixel.opacity);
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          pixel.index=unsharp_indexes[x]-(MagickRealType) indexes[x];
+          if (fabs(2.0*pixel.index) < quantum_threshold)
+            pixel.index=(MagickRealType) unsharp_indexes[x];
+          else
+            pixel.index=(MagickRealType) unsharp_indexes[x]+(pixel.index*
+              amount);
+          unsharp_indexes[x]=RoundToQuantum(pixel.index);
+        }
+      p++;
+      q++;
+    }
+    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/magick/effect.h b/magick/effect.h
new file mode 100644
index 0000000..a775231
--- /dev/null
+++ b/magick/effect.h
@@ -0,0 +1,105 @@
+/*
+  Copyright 1999-2009 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
+
+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;
+
+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 *),
+  *DespeckleImage(const Image *,ExceptionInfo *),
+  *EdgeImage(const Image *,const double,ExceptionInfo *),
+  *EmbossImage(const Image *,const double,const double,ExceptionInfo *),
+  *GaussianBlurImage(const Image *,const double,const double,ExceptionInfo *),
+  *GaussianBlurImageChannel(const Image *,const ChannelType,const double,
+    const double,ExceptionInfo *),
+  *MedianFilterImage(const Image *,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 *),
+  *ReduceNoiseImage(const Image *,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 *),
+  *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/magick/enhance.c b/magick/enhance.c
new file mode 100644
index 0000000..f1a9612
--- /dev/null
+++ b/magick/enhance.c
@@ -0,0 +1,3680 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%              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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/composite-private.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/histogram.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/resample.h"
+#include "magick/resample-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/token.h"
+#include "magick/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 LevelImage 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
+    mean,junk,gamma;
+
+  if ((channel & SyncChannels) != 0 )
+    {
+      /*
+        Apply gamma correction equally accross all given channels
+      */
+      GetImageChannelMean(image, channel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //return GammaImageChannel(image, channel, gamma);
+      return LevelImageChannel(image, channel,
+                               0.0, (double)QuantumRange, gamma);
+    }
+
+  /*
+    auto-gamma each channel separateally
+  */
+  status = MagickTrue;
+  if ((channel & RedChannel) != 0)
+    {
+      GetImageChannelMean(image, RedChannel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //status = status && GammaImageChannel(image, RedChannel, gamma);
+      status = status && LevelImageChannel(image, RedChannel,
+                               0.0, (double)QuantumRange, gamma);
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      GetImageChannelMean(image, GreenChannel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //status = status && GammaImageChannel(image, GreenChannel, gamma);
+      status = status && LevelImageChannel(image, GreenChannel,
+                               0.0, (double)QuantumRange, gamma);
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      GetImageChannelMean(image, BlueChannel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //status = status && GammaImageChannel(image, BlueChannel, gamma);
+      status = status && LevelImageChannel(image, BlueChannel,
+                               0.0, (double)QuantumRange, gamma);
+    }
+  if (((channel & OpacityChannel) != 0) &&
+      (image->matte == MagickTrue))
+    {
+      GetImageChannelMean(image, OpacityChannel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //status = status && GammaImageChannel(image, OpacityChannel, gamma);
+      status = status && LevelImageChannel(image, OpacityChannel,
+                               0.0, (double)QuantumRange, gamma);
+    }
+  if (((channel & IndexChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    {
+      GetImageChannelMean(image, IndexChannel, &mean, &junk, &image->exception);
+      gamma = log(mean*QuantumScale)/log(0.5);
+      //status = status && GammaImageChannel(image, IndexChannel, gamma);
+      status = status && LevelImageChannel(image, IndexChannel,
+                               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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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;
+
+  char
+    token[MaxTextExtent];
+
+  ColorCorrection
+    color_correction;
+
+  const char
+    *content,
+    *p;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  PixelPacket
+    *cdl_map;
+
+  register long
+    i;
+
+  XMLTreeInfo
+    *cc,
+    *ccc,
+    *sat,
+    *sop;
+
+  CacheView
+    *image_view;
+
+  /*
+    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=atof(token); break;
+              case 1: color_correction.green.slope=atof(token); break;
+              case 2: color_correction.blue.slope=atof(token); 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=atof(token); break;
+              case 1: color_correction.green.offset=atof(token); break;
+              case 2: color_correction.blue.offset=atof(token); 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=atof(token); break;
+              case 1: color_correction.green.power=atof(token); break;
+              case 2: color_correction.blue.power=atof(token); 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=atof(token);
+        }
+    }
+  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(guided)
+#endif
+  for (i=0; i <= (long) MaxMap; i++)
+  {
+    cdl_map[i].red=RoundToQuantum((MagickRealType) ScaleMapToQuantum((
+      MagickRealType) (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
+      color_correction.red.offset,color_correction.red.power)))));
+    cdl_map[i].green=RoundToQuantum((MagickRealType) ScaleMapToQuantum((
+      MagickRealType) (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
+      color_correction.green.offset,color_correction.green.power)))));
+    cdl_map[i].blue=RoundToQuantum((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 < (long) 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=RoundToQuantum(luma+color_correction.saturation*
+          cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
+        image->colormap[i].green=RoundToQuantum(luma+
+          color_correction.saturation*cdl_map[ScaleQuantumToMap(
+          image->colormap[i].green)].green-luma);
+        image->colormap[i].blue=RoundToQuantum(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 < (long) image->rows; y++)
+  {
+    double
+      luma;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      luma=0.2126*q->red+0.7152*q->green+0.0722*q->blue;
+      q->red=RoundToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(q->red)].red-luma));
+      q->green=RoundToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(q->green)].green-luma));
+      q->blue=RoundToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(q->blue)].blue-luma));
+      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_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 ClutImageTag  "Clut/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    adjust,
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  ResampleFilter
+    **resample_filter;
+
+  CacheView
+    *image_view;
+
+  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 image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(clut_image,&zero);
+  adjust=clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1;
+  exception=(&image->exception);
+  resample_filter=AcquireResampleFilterThreadSet(clut_image,MagickTrue,
+    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 < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) image->columns; x++)
+    {
+      /*
+        PROGRAMMERS WARNING:
+
+        Apply OpacityChannel BEFORE the color channels.  Do not re-order.
+
+        The handling special case 2 (coloring gray-scale), requires access to
+        the unmodified colors of the original image to determine the index
+        value.  As such alpha/matte channel handling must be performed BEFORE,
+        any of the color channels are modified.
+
+      */
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (clut_image->matte == MagickFalse)
+            {
+              /*
+                A gray-scale LUT replacement for an image alpha channel.
+              */
+              (void) ResamplePixelColor(resample_filter[id],QuantumScale*
+                (QuantumRange-q->opacity)*(clut_image->columns+adjust),
+                QuantumScale*(QuantumRange-q->opacity)*(clut_image->rows+
+                adjust),&pixel);
+              q->opacity=(Quantum) (QuantumRange-MagickPixelIntensityToQuantum(
+                &pixel));
+            }
+          else
+            if (image->matte == MagickFalse)
+              {
+                /*
+                  A greyscale image being colored by a LUT with transparency.
+                */
+                (void) ResamplePixelColor(resample_filter[id],QuantumScale*
+                  PixelIntensity(q)*(clut_image->columns-adjust),QuantumScale*
+                  PixelIntensity(q)*(clut_image->rows-adjust),&pixel);
+                q->opacity=RoundToQuantum(pixel.opacity);
+              }
+            else
+              {
+                /*
+                  Direct alpha channel lookup.
+                */
+                (void) ResamplePixelColor(resample_filter[id],QuantumScale*
+                  q->opacity*(clut_image->columns-adjust),QuantumScale*
+                  q->opacity* (clut_image->rows-adjust),&pixel);
+                q->opacity=RoundToQuantum(pixel.opacity);
+              }
+        }
+      if ((channel & RedChannel) != 0)
+        {
+          (void) ResamplePixelColor(resample_filter[id],QuantumScale*q->red*
+            (clut_image->columns-adjust),QuantumScale*q->red*
+            (clut_image->rows-adjust),&pixel);
+          q->red=RoundToQuantum(pixel.red);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          (void) ResamplePixelColor(resample_filter[id],QuantumScale*q->green*
+            (clut_image->columns-adjust),QuantumScale*q->green*
+            (clut_image->rows-adjust),&pixel);
+          q->green=RoundToQuantum(pixel.green);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          (void) ResamplePixelColor(resample_filter[id],QuantumScale*q->blue*
+            (clut_image->columns-adjust),QuantumScale*q->blue*
+            (clut_image->rows-adjust),&pixel);
+          q->blue=RoundToQuantum(pixel.blue);
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          (void) ResamplePixelColor(resample_filter[id],QuantumScale*indexes[x]*
+            (clut_image->columns-adjust),QuantumScale*indexes[x]*
+            (clut_image->rows-adjust),&pixel);
+          indexes[x]=RoundToQuantum(pixel.index);
+        }
+      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_ClutImageChannel)
+#endif
+        proceed=SetImageProgress(image,ClutImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  /*
+    Enable alpha channel if CLUT image could enable it.
+  */
+  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(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"
+
+  ExceptionInfo
+    *exception;
+
+  int
+    sign;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  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 < (long) 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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      Contrast(sign,&q->red,&q->green,&q->blue);
+      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_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 unsigned long 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"
+
+  double
+    intensity;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    black,
+    *histogram,
+    *stretch_map,
+    white;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*histogram));
+  stretch_map=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*stretch_map));
+  if ((histogram == (MagickPixelPacket *) NULL) ||
+      (stretch_map == (MagickPixelPacket *) 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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (channel == DefaultChannels)
+      for (x=0; x < (long) image->columns; x++)
+      {
+        Quantum
+          intensity;
+
+        intensity=PixelIntensityToQuantum(p);
+        histogram[ScaleQuantumToMap(intensity)].red++;
+        histogram[ScaleQuantumToMap(intensity)].green++;
+        histogram[ScaleQuantumToMap(intensity)].blue++;
+        histogram[ScaleQuantumToMap(intensity)].index++;
+        p++;
+      }
+    else
+      for (x=0; x < (long) image->columns; x++)
+      {
+        if ((channel & RedChannel) != 0)
+          histogram[ScaleQuantumToMap(p->red)].red++;
+        if ((channel & GreenChannel) != 0)
+          histogram[ScaleQuantumToMap(p->green)].green++;
+        if ((channel & BlueChannel) != 0)
+          histogram[ScaleQuantumToMap(p->blue)].blue++;
+        if ((channel & OpacityChannel) != 0)
+          histogram[ScaleQuantumToMap(p->opacity)].opacity++;
+        if (((channel & IndexChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          histogram[ScaleQuantumToMap(indexes[x])].index++;
+        p++;
+      }
+  }
+  /*
+    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 <= (long) MaxMap; i++)
+      {
+        intensity+=histogram[i].red;
+        if (intensity > black_point)
+          break;
+      }
+      black.red=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(long) 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 <= (long) MaxMap; i++)
+      {
+        intensity+=histogram[i].green;
+        if (intensity > black_point)
+          break;
+      }
+      black.green=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(long) 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 <= (long) MaxMap; i++)
+      {
+        intensity+=histogram[i].blue;
+        if (intensity > black_point)
+          break;
+      }
+      black.blue=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(long) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].blue;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.blue=(MagickRealType) i;
+    }
+  black.opacity=0.0;
+  white.opacity=MaxRange(QuantumRange);
+  if ((channel & OpacityChannel) != 0)
+    {
+      intensity=0.0;
+      for (i=0; i <= (long) MaxMap; i++)
+      {
+        intensity+=histogram[i].opacity;
+        if (intensity > black_point)
+          break;
+      }
+      black.opacity=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(long) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].opacity;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.opacity=(MagickRealType) i;
+    }
+  black.index=0.0;
+  white.index=MaxRange(QuantumRange);
+  if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
+    {
+      intensity=0.0;
+      for (i=0; i <= (long) MaxMap; i++)
+      {
+        intensity+=histogram[i].index;
+        if (intensity > black_point)
+          break;
+      }
+      black.index=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(long) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].index;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.index=(MagickRealType) i;
+    }
+  histogram=(MagickPixelPacket *) 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 <= (long) MaxMap; i++)
+  {
+    if ((channel & RedChannel) != 0)
+      {
+        if (i < (long) black.red)
+          stretch_map[i].red=0.0;
+        else
+          if (i > (long) 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 < (long) black.green)
+          stretch_map[i].green=0.0;
+        else
+          if (i > (long) 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 < (long) black.blue)
+          stretch_map[i].blue=0.0;
+        else
+          if (i > (long) 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 < (long) black.opacity)
+          stretch_map[i].opacity=0.0;
+        else
+          if (i > (long) white.opacity)
+            stretch_map[i].opacity=(MagickRealType) QuantumRange;
+          else
+            if (black.opacity != white.opacity)
+              stretch_map[i].opacity=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.opacity)/(white.opacity-
+                black.opacity)));
+      }
+    if (((channel & IndexChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      {
+        if (i < (long) black.index)
+          stretch_map[i].index=0.0;
+        else
+          if (i > (long) white.index)
+            stretch_map[i].index=(MagickRealType) QuantumRange;
+          else
+            if (black.index != white.index)
+              stretch_map[i].index=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.index)/(white.index-
+                black.index)));
+      }
+  }
+  /*
+    Stretch the image.
+  */
+  if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 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 < (long) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          {
+            if (black.red != white.red)
+              image->colormap[i].red=RoundToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].red)].red);
+          }
+        if ((channel & GreenChannel) != 0)
+          {
+            if (black.green != white.green)
+              image->colormap[i].green=RoundToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].green)].green);
+          }
+        if ((channel & BlueChannel) != 0)
+          {
+            if (black.blue != white.blue)
+              image->colormap[i].blue=RoundToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].blue)].blue);
+          }
+        if ((channel & OpacityChannel) != 0)
+          {
+            if (black.opacity != white.opacity)
+              image->colormap[i].opacity=RoundToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].opacity)].opacity);
+          }
+      }
+    }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          if (black.red != white.red)
+            q->red=RoundToQuantum(stretch_map[ScaleQuantumToMap(q->red)].red);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          if (black.green != white.green)
+            q->green=RoundToQuantum(stretch_map[ScaleQuantumToMap(
+              q->green)].green);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          if (black.blue != white.blue)
+            q->blue=RoundToQuantum(stretch_map[ScaleQuantumToMap(
+              q->blue)].blue);
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (black.opacity != white.opacity)
+            q->opacity=RoundToQuantum(stretch_map[ScaleQuantumToMap(
+              q->opacity)].opacity);
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if (black.index != white.index)
+            indexes[x]=(IndexPacket) RoundToQuantum(stretch_map[
+              ScaleQuantumToMap(indexes[x])].index);
+        }
+      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_ContrastStretchImageChannel)
+#endif
+        proceed=SetImageProgress(image,ContrastStretchImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  stretch_map=(MagickPixelPacket *) 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) r->red+pixel.red)/2; \
+  distance=(MagickRealType) r->red-(MagickRealType) pixel.red; \
+  distance_squared=QuantumScale*(2.0*((MagickRealType) QuantumRange+1.0)+ \
+     mean)*distance*distance; \
+  mean=((MagickRealType) r->green+pixel.green)/2; \
+  distance=(MagickRealType) r->green-(MagickRealType) pixel.green; \
+  distance_squared+=4.0*distance*distance; \
+  mean=((MagickRealType) r->blue+pixel.blue)/2; \
+  distance=(MagickRealType) r->blue-(MagickRealType) pixel.blue; \
+  distance_squared+=QuantumScale*(3.0*((MagickRealType) \
+    QuantumRange+1.0)-1.0-mean)*distance*distance; \
+  mean=((MagickRealType) r->opacity+pixel.opacity)/2; \
+  distance=(MagickRealType) r->opacity-(MagickRealType) pixel.opacity; \
+  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)*r->red; \
+      aggregate.green+=(weight)*r->green; \
+      aggregate.blue+=(weight)*r->blue; \
+      aggregate.opacity+=(weight)*r->opacity; \
+      total_weight+=(weight); \
+    } \
+  r++;
+#define EnhanceImageTag  "Enhance/Image"
+
+  Image
+    *enhance_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  CacheView
+    *enhance_view,
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickPixelPacket
+        aggregate;
+
+      MagickRealType
+        distance,
+        distance_squared,
+        mean,
+        total_weight;
+
+      PixelPacket
+        pixel;
+
+      register const PixelPacket
+        *__restrict r;
+
+      /*
+        Compute weighted average of target pixel color components.
+      */
+      aggregate=zero;
+      total_weight=0.0;
+      r=p+2*(image->columns+4)+2;
+      pixel=(*r);
+      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);
+      q->red=(Quantum) ((aggregate.red+(total_weight/2)-1)/total_weight);
+      q->green=(Quantum) ((aggregate.green+(total_weight/2)-1)/total_weight);
+      q->blue=(Quantum) ((aggregate.blue+(total_weight/2)-1)/total_weight);
+      q->opacity=(Quantum) ((aggregate.opacity+(total_weight/2)-1)/
+        total_weight);
+      p++;
+      q++;
+    }
+    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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    black,
+    *equalize_map,
+    *histogram,
+    intensity,
+    *map,
+    white;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*equalize_map));
+  histogram=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*histogram));
+  map=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
+  if ((equalize_map == (MagickPixelPacket *) NULL) ||
+      (histogram == (MagickPixelPacket *) NULL) ||
+      (map == (MagickPixelPacket *) NULL))
+    {
+      if (map != (MagickPixelPacket *) NULL)
+        map=(MagickPixelPacket *) RelinquishMagickMemory(map);
+      if (histogram != (MagickPixelPacket *) NULL)
+        histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
+      if (equalize_map != (MagickPixelPacket *) NULL)
+        equalize_map=(MagickPixelPacket *) 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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        histogram[ScaleQuantumToMap(p->red)].red++;
+      if ((channel & GreenChannel) != 0)
+        histogram[ScaleQuantumToMap(p->green)].green++;
+      if ((channel & BlueChannel) != 0)
+        histogram[ScaleQuantumToMap(p->blue)].blue++;
+      if ((channel & OpacityChannel) != 0)
+        histogram[ScaleQuantumToMap(p->opacity)].opacity++;
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        histogram[ScaleQuantumToMap(indexes[x])].index++;
+      p++;
+    }
+  }
+  /*
+    Integrate the histogram to get the equalization map.
+  */
+  (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
+  for (i=0; i <= (long) 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 & OpacityChannel) != 0)
+      intensity.opacity+=histogram[i].opacity;
+    if (((channel & IndexChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      intensity.index+=histogram[i].index;
+    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 <= (long) 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 & OpacityChannel) != 0) && (white.opacity != black.opacity))
+      equalize_map[i].opacity=(MagickRealType) ScaleMapToQuantum(
+        (MagickRealType) ((MaxMap*(map[i].opacity-black.opacity))/
+        (white.opacity-black.opacity)));
+    if ((((channel & IndexChannel) != 0) &&
+        (image->colorspace == CMYKColorspace)) &&
+        (white.index != black.index))
+      equalize_map[i].index=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+        ((MaxMap*(map[i].index-black.index))/(white.index-black.index)));
+  }
+  histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
+  map=(MagickPixelPacket *) 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 < (long) image->colors; i++)
+      {
+        if (((channel & RedChannel) != 0) && (white.red != black.red))
+          image->colormap[i].red=RoundToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].red)].red);
+        if (((channel & GreenChannel) != 0) && (white.green != black.green))
+          image->colormap[i].green=RoundToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].green)].green);
+        if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
+          image->colormap[i].blue=RoundToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].blue)].blue);
+        if (((channel & OpacityChannel) != 0) &&
+            (white.opacity != black.opacity))
+          image->colormap[i].opacity=RoundToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].opacity)].opacity);
+      }
+    }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (((channel & RedChannel) != 0) && (white.red != black.red))
+        q->red=RoundToQuantum(equalize_map[ScaleQuantumToMap(q->red)].red);
+      if (((channel & GreenChannel) != 0) && (white.green != black.green))
+        q->green=RoundToQuantum(equalize_map[ScaleQuantumToMap(
+          q->green)].green);
+      if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
+        q->blue=RoundToQuantum(equalize_map[ScaleQuantumToMap(q->blue)].blue);
+      if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
+        q->opacity=RoundToQuantum(equalize_map[ScaleQuantumToMap(
+          q->opacity)].opacity);
+      if ((((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace)) &&
+          (white.index != black.index))
+        indexes[x]=RoundToQuantum(equalize_map[ScaleQuantumToMap(
+          indexes[x])].index);
+      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_EqualizeImageChannel)
+#endif
+        proceed=SetImageProgress(image,EqualizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  equalize_map=(MagickPixelPacket *) 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 double gamma)
+%      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 gamma: the image gamma.
+%
+*/
+MagickExport MagickBooleanType GammaImage(Image *image,const char *level)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickPixelPacket
+    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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  Quantum
+    *gamma_map;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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(guided)
+#endif
+    for (i=0; i <= (long) MaxMap; i++)
+      gamma_map[i]=RoundToQuantum((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 < (long) 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)
+          {
+            if (image->matte == MagickFalse)
+              image->colormap[i].opacity=gamma_map[
+                ScaleQuantumToMap(image->colormap[i].opacity)];
+            else
+              image->colormap[i].opacity=(Quantum) QuantumRange-
+                gamma_map[ScaleQuantumToMap((Quantum) (QuantumRange-
+                image->colormap[i].opacity))];
+          }
+      }
+    }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=gamma_map[ScaleQuantumToMap(q->red)];
+      if ((channel & GreenChannel) != 0)
+        q->green=gamma_map[ScaleQuantumToMap(q->green)];
+      if ((channel & BlueChannel) != 0)
+        q->blue=gamma_map[ScaleQuantumToMap(q->blue)];
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte == MagickFalse)
+            q->opacity=gamma_map[ScaleQuantumToMap(q->opacity)];
+          else
+            q->opacity=(Quantum) QuantumRange-gamma_map[
+              ScaleQuantumToMap((Quantum) (QuantumRange-q->opacity))];
+        }
+      q++;
+    }
+    if (((channel & IndexChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      for (x=0; x < (long) image->columns; x++)
+        indexes[x]=gamma_map[ScaleQuantumToMap(indexes[x])];
+    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;
+
+  double
+    width;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  ResampleFilter
+    **resample_filter;
+
+  size_t
+    cube_size,
+    length,
+    level;
+
+  CacheView
+    *image_view;
+
+  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;
+  GetMagickPixelPacket(hald_image,&zero);
+  exception=(&image->exception);
+  resample_filter=AcquireResampleFilterThreadSet(hald_image,MagickTrue,
+    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 < (long) image->rows; y++)
+  {
+    double
+      offset;
+
+    HaldInfo
+      point;
+
+    MagickPixelPacket
+      pixel,
+      pixel1,
+      pixel2,
+      pixel3,
+      pixel4;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    pixel1=zero;
+    pixel2=zero;
+    pixel3=zero;
+    pixel4=zero;
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) image->columns; x++)
+    {
+      point.x=QuantumScale*(level-1.0)*q->red;
+      point.y=QuantumScale*(level-1.0)*q->green;
+      point.z=QuantumScale*(level-1.0)*q->blue;
+      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) ResamplePixelColor(resample_filter[id],fmod(offset,width),
+        floor(offset/width),&pixel1);
+      (void) ResamplePixelColor(resample_filter[id],fmod(offset+level,width),
+        floor((offset+level)/width),&pixel2);
+      MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
+        pixel2.opacity,point.y,&pixel3);
+      offset+=cube_size;
+      (void) ResamplePixelColor(resample_filter[id],fmod(offset,width),
+        floor(offset/width),&pixel1);
+      (void) ResamplePixelColor(resample_filter[id],fmod(offset+level,width),
+        floor((offset+level)/width),&pixel2);
+      MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
+        pixel2.opacity,point.y,&pixel4);
+      MagickPixelCompositeAreaBlend(&pixel3,pixel3.opacity,&pixel4,
+        pixel4.opacity,point.z,&pixel);
+      if ((channel & RedChannel) != 0)
+        q->red=RoundToQuantum(pixel.red);
+      if ((channel & GreenChannel) != 0)
+        q->green=RoundToQuantum(pixel.green);
+      if ((channel & BlueChannel) != 0)
+        q->blue=RoundToQuantum(pixel.blue);
+      if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
+        q->opacity=RoundToQuantum(pixel.opacity);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=RoundToQuantum(pixel.index);
+      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_HaldClutImageChannel)
+#endif
+        proceed=SetImageProgress(image,HaldClutImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  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=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
+      gamma);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l I m a g e C h a n n e l                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelImageChannel() applies the normal LevelImage() operation to just the
+%  Specific channels specified, 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 LevelizeImageChannel method is:
+%
+%      MagickBooleanType LevelImageChannel(Image *image,
+%        const ChannelType channel,black_point,white_point,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 LevelValue(x) (RoundToQuantum((MagickRealType) QuantumRange* \
+  pow(((double) (x)-black_point)/(white_point-black_point),1.0/gamma)))
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->colors; i++)
+    {
+      /*
+        Level colormap.
+      */
+      if ((channel & RedChannel) != 0)
+        image->colormap[i].red=LevelValue(image->colormap[i].red);
+      if ((channel & GreenChannel) != 0)
+        image->colormap[i].green=LevelValue(image->colormap[i].green);
+      if ((channel & BlueChannel) != 0)
+        image->colormap[i].blue=LevelValue(image->colormap[i].blue);
+      if ((channel & OpacityChannel) != 0)
+        image->colormap[i].opacity=LevelValue(image->colormap[i].opacity);
+      }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=LevelValue(q->red);
+      if ((channel & GreenChannel) != 0)
+        q->green=LevelValue(q->green);
+      if ((channel & BlueChannel) != 0)
+        q->blue=LevelValue(q->blue);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        q->opacity=LevelValue(q->opacity);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=LevelValue(indexes[x]);
+      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_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 LevelizeImageChannel(Image *image,
+  const ChannelType channel,const double black_point,const double white_point,
+  const double gamma)
+{
+#define LevelizeImageTag  "Levelize/Image"
+#define LevelizeValue(x) (RoundToQuantum(((MagickRealType) \
+  pow((double)(QuantumScale*(x)),1.0/gamma))*(white_point-black_point)+ \
+  black_point))
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) 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].opacity=LevelizeValue(image->colormap[i].opacity);
+    }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=LevelizeValue(q->red);
+      if ((channel & GreenChannel) != 0)
+        q->green=LevelizeValue(q->green);
+      if ((channel & BlueChannel) != 0)
+        q->blue=LevelizeValue(q->blue);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        q->opacity=LevelizeValue(q->opacity);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=LevelizeValue(indexes[x]);
+      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_LevelizeImageChannel)
+#endif
+        proceed=SetImageProgress(image,LevelizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l I m a g e C o l o r s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelImageColor() will map the given color to "black" and "white"
+%  values, limearly 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 seperatally.
+%
+%  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 LevelImageColors method is:
+%
+%  MagickBooleanType LevelImageColors(Image *image,const ChannelType channel,
+%    const MagickPixelPacket *black_color,const MagickPixelPacket *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)
+%
+*/
+MagickBooleanType LevelImageColors(Image *image,const ChannelType channel,
+  const MagickPixelPacket *black_color,const MagickPixelPacket *white_color,
+  const MagickBooleanType invert)
+{
+#define LevelColorImageTag  "LevelColor/Image"
+
+  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 & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        status|=LevelImageChannel(image,OpacityChannel,
+          black_color->opacity,white_color->opacity,(double) 1.0);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        status|=LevelImageChannel(image,IndexChannel,
+          black_color->index,white_color->index,(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 & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        status|=LevelizeImageChannel(image,OpacityChannel,
+          black_color->opacity,white_color->opacity,(double) 1.0);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        status|=LevelizeImageChannel(image,IndexChannel,
+          black_color->index,white_color->index,(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;
+
+  long
+    black,
+    white,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    *histogram,
+    intensity;
+
+  MagickSizeType
+    number_pixels;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=(long) image->columns-1; x >= 0; x--)
+    {
+      histogram[ScaleQuantumToMap(PixelIntensityToQuantum(p))]++;
+      p++;
+    }
+  }
+  /*
+    Find the histogram boundaries by locating the black and white point levels.
+  */
+  number_pixels=(MagickSizeType) image->columns*image->rows;
+  intensity=0.0;
+  for (black=0; black < (long) MaxMap; black++)
+  {
+    intensity+=histogram[black];
+    if (intensity >= black_point)
+      break;
+  }
+  intensity=0.0;
+  for (white=(long) 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"
+
+  ColorspaceType
+    colorspace;
+
+  const char
+    *artifact;
+
+  double
+    percent_brightness,
+    percent_hue,
+    percent_saturation;
+
+  ExceptionInfo
+    *exception;
+
+  GeometryInfo
+    geometry_info;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    Initialize gamma 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) ParseMagickOption(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 < (long) 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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      switch (colorspace)
+      {
+        case HSBColorspace:
+        {
+          ModulateHSB(percent_hue,percent_saturation,percent_brightness,
+            &q->red,&q->green,&q->blue);
+          break;
+        }
+        case HSLColorspace:
+        default:
+        {
+          ModulateHSL(percent_hue,percent_saturation,percent_brightness,
+            &q->red,&q->green,&q->blue);
+          break;
+        }
+        case HWBColorspace:
+        {
+          ModulateHWB(percent_hue,percent_saturation,percent_brightness,
+            &q->red,&q->green,&q->blue);
+          break;
+        }
+      }
+      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_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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  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 < (long) 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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        for (x=0; x < (long) image->columns; x++)
+        {
+          if ((q->red != q->green) || (q->green != q->blue))
+            {
+              q++;
+              continue;
+            }
+          if ((channel & RedChannel) != 0)
+            q->red=(Quantum) QuantumRange-q->red;
+          if ((channel & GreenChannel) != 0)
+            q->green=(Quantum) QuantumRange-q->green;
+          if ((channel & BlueChannel) != 0)
+            q->blue=(Quantum) QuantumRange-q->blue;
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=(Quantum) QuantumRange-q->opacity;
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            indexes[x]=(IndexPacket) QuantumRange-indexes[x];
+          q++;
+        }
+        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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=(Quantum) QuantumRange-q->red;
+      if ((channel & GreenChannel) != 0)
+        q->green=(Quantum) QuantumRange-q->green;
+      if ((channel & BlueChannel) != 0)
+        q->blue=(Quantum) QuantumRange-q->blue;
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=(Quantum) QuantumRange-q->opacity;
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=(IndexPacket) QuantumRange-indexes[x];
+      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_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.02;
+  white_point=(double) image->columns*image->rows*0.99;
+  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 contrast: control the "shoulder" of the contast curve.
+%
+%    o midpoint: control the "toe" of the contast curve.
+%
+*/
+
+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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    *sigmoidal_map;
+
+  register long
+    i;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 <= (long) 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 < (long) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          image->colormap[i].red=RoundToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].red)]);
+        if ((channel & GreenChannel) != 0)
+          image->colormap[i].green=RoundToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].green)]);
+        if ((channel & BlueChannel) != 0)
+          image->colormap[i].blue=RoundToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].blue)]);
+        if ((channel & OpacityChannel) != 0)
+          image->colormap[i].opacity=RoundToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].opacity)]);
+      }
+    }
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=RoundToQuantum(sigmoidal_map[ScaleQuantumToMap(q->red)]);
+      if ((channel & GreenChannel) != 0)
+        q->green=RoundToQuantum(sigmoidal_map[ScaleQuantumToMap(q->green)]);
+      if ((channel & BlueChannel) != 0)
+        q->blue=RoundToQuantum(sigmoidal_map[ScaleQuantumToMap(q->blue)]);
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=RoundToQuantum(sigmoidal_map[ScaleQuantumToMap(q->opacity)]);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=(IndexPacket) RoundToQuantum(sigmoidal_map[
+          ScaleQuantumToMap(indexes[x])]);
+      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_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/magick/enhance.h b/magick/enhance.h
new file mode 100644
index 0000000..a2ca92e
--- /dev/null
+++ b/magick/enhance.h
@@ -0,0 +1,67 @@
+/*
+  Copyright 1999-2009 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),
+  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),
+  LevelizeImageChannel(Image *,const ChannelType,const double,const double,
+    const double),
+  LevelImageColors(Image *,const ChannelType,const MagickPixelPacket *,
+    const MagickPixelPacket *, 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/magick/exception-private.h b/magick/exception-private.h
new file mode 100644
index 0000000..5b64870
--- /dev/null
+++ b/magick/exception-private.h
@@ -0,0 +1,84 @@
+/*
+  Copyright 1999-2009 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 "magick/log.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) \
+{ \
+  ExceptionInfo \
+    exception; \
+ \
+  GetExceptionInfo(&exception); \
+  (void) ThrowMagickException(&exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s'",strerror(errno)); \
+  CatchException(&exception); \
+  (void) DestroyExceptionInfo(&exception); \
+  _exit(1); \
+}
+#define ThrowFileException(exception,severity,tag,context) \
+{ \
+  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context, \
+    strerror(errno)); \
+}
+#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/magick/exception.c b/magick/exception.c
new file mode 100644
index 0000000..a3e7a22
--- /dev/null
+++ b/magick/exception.c
@@ -0,0 +1,990 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        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-2009 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 "magick/studio.h"
+#include "magick/client.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/string_.h"
+#include "magick/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;
+  AcquireSemaphoreInfo(&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;
+  RelinquishSemaphoreInfo(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;
+  AcquireSemaphoreInfo(&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 (exception->severity >= FatalErrorException)
+      MagickFatalError(p->severity,p->reason,p->description);
+    p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
+      exception->exceptions);
+  }
+  RelinquishSemaphoreInfo(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) fprintf(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) fprintf(stderr," (%s)",description);
+  (void) fprintf(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) fprintf(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) fprintf(stderr," (%s)",description);
+  (void) fprintf(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 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.
+%
+*/
+static void DefaultWarningHandler(const ExceptionType magick_unused(severity),
+  const char *reason,const char *description)
+{
+  if (reason == (char *) NULL)
+    return;
+  (void) fprintf(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) fprintf(stderr," (%s)",description);
+  (void) fprintf(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);
+  AcquireSemaphoreInfo(&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);
+  RelinquishSemaphoreInfo(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->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];
+
+#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 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 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 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) FormatMagickString(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;
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(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 unsigned long 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 unsigned long line,const ExceptionType severity,const char *tag,
+  const char *format,va_list operands)
+{
+  char
+    message[MaxTextExtent],
+    path[MaxTextExtent],
+    reason[MaxTextExtent];
+
+  const char
+    *locale;
+
+  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);
+  (void) FormatMagickString(message,MaxTextExtent,"%s @ %s/%s/%ld",reason,path,
+    function,line);
+  (void) ThrowException(exception,severity,message,(char *) NULL);
+  return(status);
+}
+
+MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception,
+  const char *module,const char *function,const unsigned long 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/magick/exception.h b/magick/exception.h
new file mode 100644
index 0000000..f5a3759
--- /dev/null
+++ b/magick/exception.h
@@ -0,0 +1,175 @@
+/*
+  Copyright 1999-2009 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 "magick/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,
+  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,
+  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,
+  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;
+
+  unsigned long
+    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 unsigned long,const ExceptionType,const char *,const char *,...)
+    magick_attribute((format (printf,7,8))),
+  ThrowMagickExceptionList(ExceptionInfo *,const char *,const char *,
+    const unsigned long,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/magick/fourier.c b/magick/fourier.c
new file mode 100644
index 0000000..bbb7996
--- /dev/null
+++ b/magick/fourier.c
@@ -0,0 +1,1261 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/fourier.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/property.h"
+#include "magick/thread-private.h"
+#if defined(MAGICKCORE_FFTW_DELEGATE)
+#include <complex.h>
+#include <fftw3.h>
+#endif
+
+/*
+  Typedef declarations.
+*/
+typedef struct _FourierInfo
+{
+  ChannelType
+    channel;
+
+  MagickBooleanType
+    modulus;
+
+  unsigned long
+    width,
+    height;
+
+  long
+    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 unsigned long width,
+  const unsigned long height,const long x_offset,const long y_offset,
+  double *fourier)
+{
+  double
+    *roll;
+
+  long
+    u,
+    v,
+    y;
+
+  register long
+    i,
+    x;
+
+  /*
+    Move the zero frequency (DC) from (0,0) to (width/2,height/2).
+  */
+  roll=(double *) AcquireQuantumMemory((size_t) width,height*sizeof(*roll));
+  if (roll == (double *) NULL)
+    return(MagickFalse);
+  i=0L;
+  for (y=0L; y < (long) height; y++)
+  {
+    if (y_offset < 0L)
+      v=((y+y_offset) < 0L) ? y+y_offset+(long) height : y+y_offset;
+    else
+      v=((y+y_offset) > ((long) height-1L)) ? y+y_offset-(long) height :
+        y+y_offset;
+    for (x=0L; x < (long) width; x++)
+    {
+      if (x_offset < 0L)
+        u=((x+x_offset) < 0L) ? x+x_offset+(long) width : x+x_offset;
+      else
+        u=((x+x_offset) > ((long) width-1L)) ? x+x_offset-(long) width :
+          x+x_offset;
+      roll[v*width+u]=fourier[i++];
+   }
+  }
+  (void) CopyMagickMemory(fourier,roll,width*height*sizeof(*roll));
+  roll=(double *) RelinquishMagickMemory(roll);
+  return(MagickTrue);
+}
+
+static MagickBooleanType ForwardQuadrantSwap(const unsigned long width,
+  const unsigned long height,double *source,double *destination)
+{
+  long
+    center,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    x;
+
+  /*
+    Swap quadrants.
+  */
+  center=(long) floor((double) width/2L)+1L;
+  status=RollFourier((unsigned long) center,height,0L,(long) height/2L,source);
+  if (status == MagickFalse)
+    return(MagickFalse);
+  for (y=0L; y < (long) height; y++)
+    for (x=0L; x < (long) (width/2L-1L); x++)
+      destination[width*y+x+width/2L]=source[center*y+x];
+  for (y=1; y < (long) height; y++)
+    for (x=0L; x < (long) (width/2L-1L); x++)
+      destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
+  for (x=0L; x < (long) (width/2L); x++)
+    destination[-x+width/2L-1L]=destination[x+width/2L+1L];
+  return(MagickTrue);
+}
+
+static void CorrectPhaseLHS(const unsigned long width,
+  const unsigned long height,double *fourier)
+{
+  long
+    y;
+
+  register long
+    x;
+
+  for (y=0L; y < (long) height; y++)
+    for (x=0L; x < (long) (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;
+
+  long
+    i,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register IndexPacket
+    *indexes;
+
+  register long
+    x;
+
+  register PixelPacket
+    *q;
+
+  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->width*
+    fourier_info->height*sizeof(*magnitude_source));
+  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*phase_source));
+  if (magnitude_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 < (long) fourier_info->height; y++)
+        for (x=0L; x < (long) 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 < (long) fourier_info->height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          q->red=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          break;
+        }
+        case GreenChannel:
+        {
+          q->green=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          break;
+        }
+        case BlueChannel:
+        {
+          q->blue=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          break;
+        }
+        case OpacityChannel:
+        {
+          q->opacity=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          break;
+        }
+        case IndexChannel:
+        {
+          indexes[x]=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          break;
+        }
+        case GrayChannels:
+        {
+          q->red=RoundToQuantum(QuantumRange*magnitude_source[i]);
+          q->green=q->red;
+          q->blue=q->red;
+          break;
+        }
+      }
+      i++;
+      q++;
+    }
+    status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
+    if (status == MagickFalse)
+      break;
+  }
+  i=0L;
+  for (y=0L; y < (long) fourier_info->height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(phase_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          q->red=RoundToQuantum(QuantumRange*phase_source[i]);
+          break;
+        }
+        case GreenChannel:
+        {
+          q->green=RoundToQuantum(QuantumRange*phase_source[i]);
+          break;
+        }
+        case BlueChannel:
+        {
+          q->blue=RoundToQuantum(QuantumRange*phase_source[i]);
+          break;
+        }
+        case OpacityChannel:
+        {
+          q->opacity=RoundToQuantum(QuantumRange*phase_source[i]);
+          break;
+        }
+        case IndexChannel:
+        {
+          indexes[x]=RoundToQuantum(QuantumRange*phase_source[i]);
+          break;
+        }
+        case GrayChannels:
+        {
+          q->red=RoundToQuantum(QuantumRange*phase_source[i]);
+          q->green=q->red;
+          q->blue=q->red;
+          break;
+        }
+      }
+      i++;
+      q++;
+    }
+    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;
+
+  long
+    y;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i,
+    x;
+
+  /*
+    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->width*fourier_info->height*
+    sizeof(*source));
+  i=0L;
+  image_view=AcquireCacheView(image);
+  for (y=0L; y < (long) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
+      exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          source[i]=QuantumScale*p->red;
+          break;
+        }
+        case GreenChannel:
+        {
+          source[i]=QuantumScale*p->green;
+          break;
+        }
+        case BlueChannel:
+        {
+          source[i]=QuantumScale*p->blue;
+          break;
+        }
+        case OpacityChannel:
+        {
+          source[i]=QuantumScale*p->opacity;
+          break;
+        }
+        case IndexChannel:
+        {
+          source[i]=QuantumScale*indexes[x];
+          break;
+        }
+        case GrayChannels:
+        {
+          source[i]=QuantumScale*p->red;
+          break;
+        }
+      }
+      i++;
+      p++;
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  fourier=(fftw_complex *) AcquireAlignedMemory((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 < (long) fourier_info->height; y++)
+    for (x=0L; x < (long) fourier_info->center; x++)
+      fourier[i++]/=n;
+  /*
+    Generate magnitude and phase (or real and imaginary).
+  */
+  i=0L;
+  if (fourier_info->modulus != MagickFalse)
+    for (y=0L; y < (long) fourier_info->height; y++)
+      for (x=0L; x < (long) fourier_info->center; x++)
+      {
+        magnitude[i]=cabs(fourier[i]);
+        phase[i]=carg(fourier[i]);
+        i++;
+      }
+  else
+    for (y=0L; y < (long) fourier_info->height; y++)
+      for (x=0L; x < (long) fourier_info->center; x++)
+      {
+        magnitude[i]=creal(fourier[i]);
+        phase[i]=cimag(fourier[i]);
+        i++;
+      }
+  fourier=(fftw_complex *) RelinquishAlignedMemory(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;
+
+  MagickBooleanType
+    status;
+
+  FourierInfo
+    fourier_info;
+
+  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=(long) 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 *) AcquireAlignedMemory((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 *) RelinquishAlignedMemory(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;
+
+    unsigned long
+      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;
+
+            register long
+              i;
+
+            phase_image->storage_class=DirectClass;
+            phase_image->depth=32UL;
+            AppendImageToList(&fourier_image,magnitude_image);
+            AppendImageToList(&fourier_image,phase_image);
+            status=MagickTrue;
+            is_gray=IsGrayImage(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,1) shared(status)
+#endif
+            for (i=0L; i < 5L; i++)
+            {
+              MagickBooleanType
+                thread_status;
+
+              thread_status=MagickTrue;
+              switch (i)
+              {
+                case 0:
+                {
+                  if (is_gray != MagickFalse)
+                    {
+                      thread_status=ForwardFourierTransformChannel(image,
+                        GrayChannels,modulus,fourier_image,exception);
+                      break;
+                    }
+                  thread_status=ForwardFourierTransformChannel(image,RedChannel,
+                    modulus,fourier_image,exception);
+                  break;
+                }
+                case 1:
+                {
+                  if (is_gray == MagickFalse)
+                    thread_status=ForwardFourierTransformChannel(image,
+                      GreenChannel,modulus,fourier_image,exception);
+                  break;
+                }
+                case 2:
+                {
+                  if (is_gray == MagickFalse)
+                    thread_status=ForwardFourierTransformChannel(image,
+                      BlueChannel,modulus,fourier_image,exception);
+                  break;
+                }
+                case 4:
+                {
+                  if (image->matte != MagickFalse)
+                    thread_status=ForwardFourierTransformChannel(image,
+                      OpacityChannel,modulus,fourier_image,exception);
+                  break;
+                }
+                case 5:
+                {
+                  if (image->colorspace == CMYKColorspace)
+                    thread_status=ForwardFourierTransformChannel(image,
+                      IndexChannel,modulus,fourier_image,exception);
+                  break;
+                }
+              }
+              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 *images,
+%        const MagickBooleanType modulus,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    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 unsigned long width,
+  const unsigned long height,const double *source,double *destination)
+{
+  long
+    center,
+    y;
+
+  register long
+    x;
+
+  /*
+    Swap quadrants.
+  */
+  center=(long) floor((double) width/2.0)+1L;
+  for (y=1L; y < (long) height; y++)
+    for (x=0L; x < (long) (width/2L+1L); x++)
+      destination[center*(height-y)-x+width/2L]=source[y*width+x];
+  for (y=0L; y < (long) 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,(long) height/-2L,destination));
+}
+
+static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
+  const Image *images,fftw_complex *fourier,ExceptionInfo *exception)
+{
+  CacheView
+    *magnitude_view,
+    *phase_view;
+
+  double
+    *magnitude,
+    *phase,
+    *magnitude_source,
+    *phase_source;
+
+  Image
+    *magnitude_image,
+    *phase_image;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i,
+    x;
+
+  /*
+    Inverse fourier - read image and break down into a double array.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  magnitude_image=GetFirstImageInList(images),
+  phase_image=GetNextImageInList(images);
+  if (phase_image == (Image *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+        "ImageSequenceRequired","`%s'",images->filename);
+      return(MagickFalse);
+    }
+  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'",images->filename);
+      return(MagickFalse);
+    }
+  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->height*sizeof(*phase_source));
+  if (phase_source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+      return(MagickFalse);
+    }
+  i=0L;
+  magnitude_view=AcquireCacheView(magnitude_image);
+  for (y=0L; y < (long) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
+      exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          magnitude_source[i]=QuantumScale*p->red;
+          break;
+        }
+        case GreenChannel:
+        {
+          magnitude_source[i]=QuantumScale*p->green;
+          break;
+        }
+        case BlueChannel:
+        {
+          magnitude_source[i]=QuantumScale*p->blue;
+          break;
+        }
+        case OpacityChannel:
+        {
+          magnitude_source[i]=QuantumScale*p->opacity;
+          break;
+        }
+        case IndexChannel:
+        {
+          magnitude_source[i]=QuantumScale*indexes[x];
+          break;
+        }
+        case GrayChannels:
+        {
+          magnitude_source[i]=QuantumScale*p->red;
+          break;
+        }
+      }
+      i++;
+      p++;
+    }
+  }
+  i=0L;
+  phase_view=AcquireCacheView(phase_image);
+  for (y=0L; y < (long) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
+      exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(phase_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          phase_source[i]=QuantumScale*p->red;
+          break;
+        }
+        case GreenChannel:
+        {
+          phase_source[i]=QuantumScale*p->green;
+          break;
+        }
+        case BlueChannel:
+        {
+          phase_source[i]=QuantumScale*p->blue;
+          break;
+        }
+        case OpacityChannel:
+        {
+          phase_source[i]=QuantumScale*p->opacity;
+          break;
+        }
+        case IndexChannel:
+        {
+          phase_source[i]=QuantumScale*indexes[x];
+          break;
+        }
+        case GrayChannels:
+        {
+          phase_source[i]=QuantumScale*p->red;
+          break;
+        }
+      }
+      i++;
+      p++;
+    }
+  }
+  if (fourier_info->modulus != MagickFalse)
+    {
+      i=0L;
+      for (y=0L; y < (long) fourier_info->height; y++)
+        for (x=0L; x < (long) 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'",images->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->width,
+    fourier_info->height*sizeof(*phase));
+  if (phase == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->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 < (long) fourier_info->height; y++)
+       for (x=0L; x < (long) fourier_info->center; x++)
+       {
+         fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
+         i++;
+      }
+  else
+    for (y=0L; y < (long) fourier_info->height; y++)
+      for (x=0L; x < (long) fourier_info->center; x++)
+      {
+        fourier[i]=magnitude[i]+I*phase[i];
+        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;
+
+  long
+    y;
+
+  register IndexPacket
+    *indexes;
+
+  register long
+    i,
+    x;
+
+  register PixelPacket
+    *q;
+
+  source=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
+    fourier_info->height*sizeof(double));
+  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 < (long) fourier_info->height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width,1UL,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0L; x < (long) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          q->red=RoundToQuantum(QuantumRange*source[i]);
+          break;
+        }
+        case GreenChannel:
+        {
+          q->green=RoundToQuantum(QuantumRange*source[i]);
+          break;
+        }
+        case BlueChannel:
+        {
+          q->blue=RoundToQuantum(QuantumRange*source[i]);
+          break;
+        }
+        case OpacityChannel:
+        {
+          q->opacity=RoundToQuantum(QuantumRange*source[i]);
+          break;
+        }
+        case IndexChannel:
+        {
+          indexes[x]=RoundToQuantum(QuantumRange*source[i]);
+          break;
+        }
+        case GrayChannels:
+        {
+          q->red=RoundToQuantum(QuantumRange*source[i]);
+          q->green=q->red;
+          q->blue=q->red;
+          break;
+        }
+      }
+      i++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  source=(double *) RelinquishMagickMemory(source);
+  return(MagickTrue);
+}
+
+static MagickBooleanType InverseFourierTransformChannel(const Image *images,
+  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=images->columns;
+  if ((images->columns != images->rows) || ((images->columns % 2) != 0) ||
+      ((images->rows % 2) != 0))
+    {
+      extent=images->columns < images->rows ? images->rows : images->columns;
+      fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
+    }
+  fourier_info.height=fourier_info.width;
+  fourier_info.center=(long) 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(double));
+  if (magnitude == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      return(MagickFalse);
+    }
+  phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(double));
+  if (phase == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*fourier));
+  if (fourier == (fftw_complex *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      phase=(double *) RelinquishMagickMemory(phase);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  status=InverseFourier(&fourier_info,images,fourier,exception);
+  if (status != MagickFalse)
+    status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
+      exception);
+  fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
+  phase=(double *) RelinquishMagickMemory(phase);
+  magnitude=(double *) RelinquishMagickMemory(magnitude);
+  return(status);
+}
+#endif
+
+MagickExport Image *InverseFourierTransformImage(const Image *images,
+  const MagickBooleanType modulus,ExceptionInfo *exception)
+{
+  Image
+    *fourier_image;
+
+#if !defined(MAGICKCORE_FFTW_DELEGATE)
+  fourier_image=(Image *) NULL;
+  (void) modulus;
+  (void) ThrowMagickException(exception,GetMagickModule(),
+    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
+    images->filename);
+#else
+  {
+    fourier_image=CloneImage(images,images->columns,images->rows,MagickFalse,
+      exception);
+    if (fourier_image != (Image *) NULL)
+      {
+        MagickBooleanType
+          is_gray,
+          status;
+
+        register long
+          i;
+
+        status=MagickTrue;
+        is_gray=IsGrayImage(images,exception);
+        if ((is_gray != MagickFalse) && (images->next != (Image *) NULL))
+          is_gray=IsGrayImage(images->next,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp parallel for schedule(dynamic,1) shared(status)
+#endif
+        for (i=0L; i < 5L; i++)
+        {
+          MagickBooleanType
+            thread_status;
+
+          thread_status=MagickTrue;
+          switch (i)
+          {
+            case 0:
+            {
+              if (is_gray != MagickFalse)
+                {
+                  thread_status=InverseFourierTransformChannel(images,
+                    GrayChannels,modulus,fourier_image,exception);
+                  break;
+                }
+              thread_status=InverseFourierTransformChannel(images,RedChannel,
+                modulus,fourier_image,exception);
+              break;
+            }
+            case 1:
+            {
+              if (is_gray == MagickFalse)
+                thread_status=InverseFourierTransformChannel(images,
+                  GreenChannel,modulus,fourier_image,exception);
+              break;
+            }
+            case 2:
+            {
+              if (is_gray == MagickFalse)
+                thread_status=InverseFourierTransformChannel(images,BlueChannel,
+                  modulus,fourier_image,exception);
+              break;
+            }
+            case 3:
+            {
+              if (images->matte != MagickFalse)
+                thread_status=InverseFourierTransformChannel(images,
+                  OpacityChannel,modulus,fourier_image,exception);
+              break;
+            }
+            case 4:
+            {
+              if (images->colorspace == CMYKColorspace)
+                thread_status=InverseFourierTransformChannel(images,
+                  IndexChannel,modulus,fourier_image,exception);
+              break;
+            }
+          }
+          if (thread_status == MagickFalse)
+            status=thread_status;
+        }
+        if (status == MagickFalse)
+          fourier_image=DestroyImage(fourier_image);
+      }
+      fftw_cleanup();
+  }
+#endif
+  return(fourier_image);
+}
diff --git a/magick/fourier.h b/magick/fourier.h
new file mode 100644
index 0000000..783fbd7
--- /dev/null
+++ b/magick/fourier.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2009 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 MagickBooleanType,
+   ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/fx-private.h b/magick/fx-private.h
new file mode 100644
index 0000000..e4a94e1
--- /dev/null
+++ b/magick/fx-private.h
@@ -0,0 +1,41 @@
+/*
+  Copyright 1999-2009 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 long,const long,
+    MagickRealType *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/fx.c b/magick/fx.c
new file mode 100644
index 0000000..1dc9ce9
--- /dev/null
+++ b/magick/fx.c
@@ -0,0 +1,6219 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                 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-2009 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 "magick/studio.h"
+#include "magick/annotate.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/composite.h"
+#include "magick/decorate.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/fx-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/random-private.h"
+#include "magick/resample.h"
+#include "magick/resample-private.h"
+#include "magick/resize.h"
+#include "magick/shear.h"
+#include "magick/splay-tree.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/transform.h"
+#include "magick/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
+
+struct _FxInfo
+{
+  const Image
+    *images;
+
+  MagickBooleanType
+    matte;
+
+  char
+    *expression;
+
+  FILE
+    *file;
+
+  SplayTreeInfo
+    *colors,
+    *symbols;
+
+  ResampleFilter
+    **resample_filter;
+
+  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];
+
+  FxInfo
+    *fx_info;
+
+  register long
+    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->matte=image->matte;
+  fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+    RelinquishMagickMemory);
+  fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+    RelinquishMagickMemory);
+  fx_info->resample_filter=(ResampleFilter **) AcquireQuantumMemory(
+    GetImageListLength(fx_info->images),sizeof(*fx_info->resample_filter));
+  if (fx_info->resample_filter == (ResampleFilter **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  for (i=0; i < (long) GetImageListLength(fx_info->images); i++)
+  {
+    fx_info->resample_filter[i]=AcquireResampleFilter(GetImageFromList(
+      fx_info->images,i),fx_info->exception);
+    SetResampleFilter(fx_info->resample_filter[i],PointFilter,1.0);
+  }
+  fx_info->random_info=AcquireRandomInfo();
+  fx_info->expression=ConstantString(expression);
+  fx_info->file=stderr;
+  (void) SubstituteString(&fx_info->expression," ","");  /* compact string */
+  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-","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^-");
+    }
+  /*
+    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);
+  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"
+
+  const char
+    *option;
+
+  Image
+    *noise_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    attenuate;
+
+  RandomInfo
+    **random_info;
+
+  CacheView
+    *image_view,
+    *noise_view;
+
+  /*
+    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=atof(option);
+  status=MagickTrue;
+  progress=0;
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(image);
+  noise_view=AcquireCacheView(noise_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT_DEBUG)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict noise_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__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 == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
+          p->red,noise_type,attenuate));
+      if ((channel & GreenChannel) != 0)
+        q->green=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
+          p->green,noise_type,attenuate));
+      if ((channel & BlueChannel) != 0)
+        q->blue=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
+          p->blue,noise_type,attenuate));
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
+          p->opacity,noise_type,attenuate));
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        noise_indexes[x]=(IndexPacket) RoundToQuantum(GenerateDifferentialNoise(
+          random_info[id],indexes[x],noise_type,attenuate));
+      p++;
+      q++;
+    }
+    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_AverageImages)
+#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"
+
+  Image
+    *shift_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view,
+    *shift_view;
+
+  /*
+    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_DEBUG)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    MagickPixelPacket
+      pixel;
+
+    Quantum
+      quantum;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      quantum=p->red;
+      if (p->green < quantum)
+        quantum=p->green;
+      if (p->blue < quantum)
+        quantum=p->blue;
+      pixel.red=0.5*(p->red+factor*quantum);
+      pixel.green=0.5*(p->green+factor*quantum);
+      pixel.blue=0.5*(p->blue+factor*quantum);
+      quantum=p->red;
+      if (p->green > quantum)
+        quantum=p->green;
+      if (p->blue > quantum)
+        quantum=p->blue;
+      pixel.red=0.5*(pixel.red+factor*quantum);
+      pixel.green=0.5*(pixel.green+factor*quantum);
+      pixel.blue=0.5*(pixel.blue+factor*quantum);
+      q->red=RoundToQuantum(pixel.red);
+      q->green=RoundToQuantum(pixel.green);
+      q->blue=RoundToQuantum(pixel.blue);
+      p++;
+      q++;
+    }
+    sync=SyncCacheViewAuthenticPixels(shift_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT_DEBUG)
+  #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"
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *colorize_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    pixel;
+
+  MagickStatusType
+    flags;
+
+  CacheView
+    *colorize_view,
+    *image_view;
+
+  /*
+    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.opacity=(MagickRealType) OpaqueOpacity;
+  if ((flags & SigmaValue) != 0)
+    pixel.green=geometry_info.sigma;
+  if ((flags & XiValue) != 0)
+    pixel.blue=geometry_info.xi;
+  if ((flags & PsiValue) != 0)
+    pixel.opacity=geometry_info.psi;
+  /*
+    Colorize DirectClass image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  colorize_view=AcquireCacheView(colorize_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT_DEBUG)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      q->red=(Quantum) ((p->red*(100.0-pixel.red)+
+        colorize.red*pixel.red)/100.0);
+      q->green=(Quantum) ((p->green*(100.0-pixel.green)+
+        colorize.green*pixel.green)/100.0);
+      q->blue=(Quantum) ((p->blue*(100.0-pixel.blue)+
+        colorize.blue*pixel.blue)/100.0);
+      q->opacity=(Quantum) ((p->opacity*(100.0-pixel.opacity)+
+        colorize.opacity*pixel.opacity)/100.0);
+      p++;
+      q++;
+    }
+    sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT_DEBUG)
+  #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 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 unsigned long order,
+%        const double *kernel,ExceptionInfo *exception)
+%      Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
+%        const unsigned long 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 unsigned long 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 unsigned long order,const double *kernel,
+  ExceptionInfo *exception)
+{
+#define ConvolveImageTag  "Convolve/Image"
+
+  double
+    *normal_kernel;
+
+  Image
+    *convolve_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    bias,
+    gamma;
+
+  register long
+    i;
+
+  unsigned long
+    width;
+
+  CacheView
+    *convolve_view,
+    *image_view;
+
+  /*
+    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;
+
+      long
+        u,
+        v;
+
+      register const double
+        *k;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  ConvolveImage with %ldx%ld kernel:",width,width);
+      message=AcquireString("");
+      k=kernel;
+      for (v=0; v < (long) width; v++)
+      {
+        *message='\0';
+        (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (long) width; u++)
+        {
+          (void) FormatMagickString(format,MaxTextExtent,"%+f ",*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 < (long) (width*width); i++)
+    gamma+=kernel[i];
+  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+  for (i=0; i < (long) (width*width); i++)
+    normal_kernel[i]=gamma*kernel[i];
+  /*
+    Convolve image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(image,&zero);
+  bias=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 < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict convolve_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
+      2L),image->columns+width,width,exception);
+    q=GetCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    convolve_indexes=GetCacheViewAuthenticIndexQueue(convolve_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      long
+        v;
+
+      MagickPixelPacket
+        pixel;
+
+      register const double
+        *__restrict k;
+
+      register const PixelPacket
+        *__restrict kernel_pixels;
+
+      register long
+        u;
+
+      pixel=zero;
+      k=normal_kernel;
+      kernel_pixels=p;
+      if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (v=0; v < (long) width; v++)
+          {
+            for (u=0; u < (long) width; u++)
+            {
+              pixel.red+=(*k)*kernel_pixels[u].red;
+              pixel.green+=(*k)*kernel_pixels[u].green;
+              pixel.blue+=(*k)*kernel_pixels[u].blue;
+              k++;
+            }
+            kernel_pixels+=image->columns+width;
+          }
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=normal_kernel;
+              kernel_pixels=p;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  pixel.opacity+=(*k)*kernel_pixels[u].opacity;
+                  k++;
+                }
+                kernel_pixels+=image->columns+width;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=normal_kernel;
+              kernel_indexes=indexes;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  pixel.index+=(*k)*kernel_indexes[u];
+                  k++;
+                }
+                kernel_indexes+=image->columns+width;
+              }
+              convolve_indexes[x]=RoundToQuantum(pixel.index+bias);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (v=0; v < (long) width; v++)
+          {
+            for (u=0; u < (long) width; u++)
+            {
+              alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                kernel_pixels[u].opacity));
+              pixel.red+=(*k)*alpha*kernel_pixels[u].red;
+              pixel.green+=(*k)*alpha*kernel_pixels[u].green;
+              pixel.blue+=(*k)*alpha*kernel_pixels[u].blue;
+              pixel.opacity+=(*k)*kernel_pixels[u].opacity;
+              gamma+=(*k)*alpha;
+              k++;
+            }
+            kernel_pixels+=image->columns+width;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(gamma*pixel.red+bias);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(gamma*pixel.green+bias);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(gamma*pixel.blue+bias);
+          if ((channel & OpacityChannel) != 0)
+            {
+              k=normal_kernel;
+              kernel_pixels=p;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  pixel.opacity+=(*k)*kernel_pixels[u].opacity;
+                  k++;
+                }
+                kernel_pixels+=image->columns+width;
+              }
+              q->opacity=RoundToQuantum(pixel.opacity+bias);
+            }
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            {
+              register const IndexPacket
+                *__restrict kernel_indexes;
+
+              k=normal_kernel;
+              kernel_pixels=p;
+              kernel_indexes=indexes;
+              for (v=0; v < (long) width; v++)
+              {
+                for (u=0; u < (long) width; u++)
+                {
+                  alpha=(MagickRealType) (QuantumScale*(QuantumRange-
+                    kernel_pixels[u].opacity));
+                  pixel.index+=(*k)*alpha*kernel_indexes[u];
+                  k++;
+                }
+                kernel_pixels+=image->columns+width;
+                kernel_indexes+=image->columns+width;
+              }
+              convolve_indexes[x]=RoundToQuantum(gamma*pixel.index+bias);
+            }
+        }
+      p++;
+      q++;
+    }
+    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 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 long
+    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=0; i < (long) GetImageListLength(fx_info->images); i++)
+    fx_info->resample_filter[i]=DestroyResampleFilter(
+      fx_info->resample_filter[i]);
+  fx_info->resample_filter=(ResampleFilter **) RelinquishMagickMemory(
+    fx_info->resample_filter);
+  fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
+  fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
+  return(fx_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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 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 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 Quantum ApplyEvaluateOperator(RandomInfo *random_info,Quantum pixel,
+  const MagickEvaluateOperator op,const MagickRealType value)
+{
+  MagickRealType
+    result;
+
+  result=0.0;
+  switch (op)
+  {
+    case UndefinedEvaluateOperator:
+      break;
+    case AddEvaluateOperator:
+    {
+      result=(MagickRealType) (pixel+value);
+      break;
+    }
+    case AddModulusEvaluateOperator:
+    {
+      /* This will return a 'floored modulus' of the addition which will
+       * always return a positive result, regardless of if the result is
+       * positive or negative, and thus in the 0 to QuantumRange range.
+       *
+       * WARNING: this is NOT the same as a % or fmod() which returns a
+       * 'truncated modulus' result, where floor() is replaced by trunc()
+       * and could return a negative result, which will be clipped.
+       */
+      result = pixel+value;
+      result -= (QuantumRange+1)*floor(result/(QuantumRange+1));
+      break;
+    }
+    case AndEvaluateOperator:
+    {
+      result=(MagickRealType) ((unsigned long) pixel & (unsigned long)
+        (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 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) ((unsigned long) pixel << (unsigned long)
+        (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 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) ((unsigned long) pixel | (unsigned long)
+        (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) ((unsigned long) pixel >> (unsigned long)
+        (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) ((unsigned long) pixel ^ (unsigned long)
+        (value+0.5));
+      break;
+    }
+  }
+  return(RoundToQuantum(result));
+}
+
+MagickExport MagickBooleanType EvaluateImage(Image *image,
+  const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=EvaluateImageChannel(image,AllChannels,op,value,exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
+  const ChannelType channel,const MagickEvaluateOperator op,const double value,
+  ExceptionInfo *exception)
+{
+#define EvaluateImageTag  "Evaluate/Image "
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RandomInfo
+    **random_info;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=ApplyEvaluateOperator(random_info[id],q->red,op,value);
+      if ((channel & GreenChannel) != 0)
+        q->green=ApplyEvaluateOperator(random_info[id],q->green,op,value);
+      if ((channel & BlueChannel) != 0)
+        q->blue=ApplyEvaluateOperator(random_info[id],q->blue,op,value);
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte == MagickFalse)
+            q->opacity=ApplyEvaluateOperator(random_info[id],q->opacity,op,
+              value);
+          else
+            q->opacity=(Quantum) QuantumRange-ApplyEvaluateOperator(
+              random_info[id],(Quantum) (QuantumRange-q->opacity),op,value);
+        }
+      if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
+        indexes[x]=(IndexPacket) ApplyEvaluateOperator(random_info[id],
+          indexes[x],op,value);
+      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_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 long number_parameters,
+%        const double *parameters,ExceptionInfo *exception)
+%      MagickBooleanType FunctionImageChannel(Image *image,
+%        const ChannelType channel,const MagickFunction function,
+%        const long 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 unsigned long number_parameters,const MagickRealType *parameters,
+  ExceptionInfo *exception)
+{
+  MagickRealType
+    result;
+
+  register long
+    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 < (long) 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=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 = MagickPI*slope*(QuantumScale*pixel - center);
+      result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
+                  result) + bias ) );
+      break;
+    }
+    case UndefinedFunction:
+      break;
+  }
+  return(RoundToQuantum(result));
+}
+
+MagickExport MagickBooleanType FunctionImage(Image *image,
+  const MagickFunction function,const unsigned long number_parameters,
+  const double *parameters,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=FunctionImageChannel(image,AllChannels,function,number_parameters,
+    parameters,exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType FunctionImageChannel(Image *image,
+  const ChannelType channel,const MagickFunction function,
+  const unsigned long number_parameters,const double *parameters,
+  ExceptionInfo *exception)
+{
+#define FunctionImageTag  "Function/Image "
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=ApplyFunction(q->red,function,number_parameters,parameters,
+          exception);
+      if ((channel & GreenChannel) != 0)
+        q->green=ApplyFunction(q->green,function,number_parameters,parameters,
+          exception);
+      if ((channel & BlueChannel) != 0)
+        q->blue=ApplyFunction(q->blue,function,number_parameters,parameters,
+          exception);
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte == MagickFalse)
+            q->opacity=ApplyFunction(q->opacity,function,number_parameters,
+              parameters,exception);
+          else
+            q->opacity=(Quantum) QuantumRange-ApplyFunction((Quantum) (
+              QuantumRange-q->opacity),function,number_parameters,parameters,
+              exception);
+        }
+      if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
+        indexes[x]=(IndexPacket) ApplyFunction(indexes[x],function,
+          number_parameters,parameters,exception);
+      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_FunctionImageChannel)
+#endif
+        proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     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 long x,const long 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 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) FormatMagickString(key,MaxTextExtent,"%p.%ld.%s",image,(long) channel,
+    symbol);
+  value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
+  if (value != (const char *) NULL)
+    return(QuantumScale*atof(value));
+  (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
+  if (LocaleNCompare(symbol,"depth",5) == 0)
+    {
+      unsigned long
+        depth;
+
+      depth=GetImageChannelDepth(image,channel,exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%lu",depth);
+    }
+  if (LocaleNCompare(symbol,"kurtosis",8) == 0)
+    {
+      double
+        kurtosis,
+        skewness;
+
+      (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
+        exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",kurtosis);
+    }
+  if (LocaleNCompare(symbol,"maxima",6) == 0)
+    {
+      double
+        maxima,
+        minima;
+
+      (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",maxima);
+    }
+  if (LocaleNCompare(symbol,"mean",4) == 0)
+    {
+      double
+        mean,
+        standard_deviation;
+
+      (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
+        exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",mean);
+    }
+  if (LocaleNCompare(symbol,"minima",6) == 0)
+    {
+      double
+        maxima,
+        minima;
+
+      (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",minima);
+    }
+  if (LocaleNCompare(symbol,"skewness",8) == 0)
+    {
+      double
+        kurtosis,
+        skewness;
+
+      (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
+        exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",skewness);
+    }
+  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
+    {
+      double
+        mean,
+        standard_deviation;
+
+      (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
+        exception);
+      (void) FormatMagickString(statistic,MaxTextExtent,"%g",
+        standard_deviation);
+    }
+  (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
+    ConstantString(statistic));
+  return(QuantumScale*atof(statistic));
+}
+
+static MagickRealType
+  FxEvaluateSubexpression(FxInfo *,const ChannelType,const long,const long,
+    const char *,MagickRealType *,ExceptionInfo *);
+
+static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
+  const long x,const long 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 long x,const long 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 long
+    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 long x,const long y,const char *expression,ExceptionInfo *exception)
+{
+  char
+    *q,
+    subexpression[MaxTextExtent],
+    symbol[MaxTextExtent];
+
+  const char
+    *p,
+    *value;
+
+  Image
+    *image;
+
+  MagickPixelPacket
+    pixel;
+
+  MagickRealType
+    alpha,
+    beta;
+
+  PointInfo
+    point;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  unsigned long
+    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=(long) (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+=(long) length;
+  i%=length;
+  image=GetImageFromList(fx_info->images,i);
+  if (image == (Image *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "NoSuchImage","`%s'",expression);
+      return(0.0);
+    }
+  (void) ResamplePixelColor(fx_info->resample_filter[i],point.x,point.y,&pixel);
+  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))
+        {
+          MagickPixelPacket
+            *color;
+
+          color=(MagickPixelPacket *) GetValueFromSplayTree(fx_info->colors,
+            name);
+          if (color != (MagickPixelPacket *) NULL)
+            {
+              pixel=(*color);
+              p+=strlen(name);
+            }
+          else
+            if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
+              {
+                (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
+                  CloneMagickPixelPacket(&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 OpacityChannel:
+        {
+          if (pixel.matte == MagickFalse)
+            {
+              fx_info->matte=MagickFalse;
+              return(1.0);
+            }
+          return((MagickRealType) (QuantumScale*(QuantumRange-pixel.opacity)));
+        }
+        case IndexChannel:
+        {
+          if (image->colorspace != CMYKColorspace)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"ColorSeparatedImageRequired","`%s'",
+                image->filename);
+              return(0.0);
+            }
+          return(QuantumScale*pixel.index);
+        }
+        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*(QuantumRange-pixel.opacity)));
+      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 OpacityChannel:
+              {
+                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 OpacityChannel:
+            {
+              if ((flags & PsiValue) == 0)
+                return(0.0);
+              return(channel_info.psi);
+            }
+            case IndexChannel:
+            {
+              if ((flags & ChiValue) == 0)
+                return(0.0);
+              return(channel_info.chi);
+            }
+            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.index);
+        }
+      break;
+    }
+    case 'H':
+    case 'h':
+    {
+      if (LocaleCompare(symbol,"h") == 0)
+        return((MagickRealType) image->rows);
+      if (LocaleCompare(symbol,"hue") == 0)
+        {
+          double
+            hue,
+            lightness,
+            saturation;
+
+          ConvertRGBToHSL(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
+            RoundToQuantum(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*MagickPixelIntensityToQuantum(&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(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
+            RoundToQuantum(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.opacity);
+      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(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
+            RoundToQuantum(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) fx_info->images->scene);
+      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) atof(value));
+  (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,
+    MultiplyPrecedence,
+    AdditionPrecedence,
+    ShiftPrecedence,
+    RelationalPrecedence,
+    EquivalencyPrecedence,
+    BitwiseAndPrecedence,
+    BitwiseOrPrecedence,
+    LogicalAndPrecedence,
+    LogicalOrPrecedence,
+    TernaryPrecedence,
+    AssignmentPrecedence,
+    CommaPrecedence,
+    SeparatorPrecedence
+  } FxPrecedence;
+
+  FxPrecedence
+    precedence,
+    target;
+
+  register const char
+    *subexpression;
+
+  register int
+    c;
+
+  unsigned long
+    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;
+      }
+    if (LocaleNCompare(expression,"atan2",5) == 0)
+      {
+        expression+=5;
+        continue;
+      }
+    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 '^':
+        {
+          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 ':':
+        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 long x,const long 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);
+    }
+  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) (~(unsigned long) *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 '*':
+        {
+          *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) ((unsigned long) (alpha+0.5) << (unsigned long)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case RightShiftOperator:
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((unsigned long) (alpha+0.5) >> (unsigned long)
+            (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) ((unsigned long) (alpha+0.5) & (unsigned long)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case '|':
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((unsigned long) (alpha+0.5) | (unsigned long)
+            (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) FormatMagickString(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) (~(unsigned long) (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 (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(((long) 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 OpacityChannel: 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 OpacityChannel: 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) fprintf(fx_info->file,"%s[%ld,%ld].%s: %s=%g\n",
+              fx_info->images->filename,x,y,type,subexpression,(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+0.5));
+        }
+      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));
+      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",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,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);
+          if (alpha >= 0.0)
+            return((MagickRealType) floor((double) alpha+0.5));
+          return((MagickRealType) ceil((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,"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 (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=strtod(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 long x,const long 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 long
+    i;
+
+  assert(fx_info != (FxInfo **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (fx_info[i] != (FxInfo *) NULL)
+      fx_info[i]=DestroyFxInfo(fx_info[i]);
+  fx_info=(FxInfo **) RelinquishAlignedMemory(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 long
+    i;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  fx_info=(FxInfo **) AcquireAlignedMemory(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 < (long) 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"
+
+  FxInfo
+    **fx_info;
+
+  Image
+    *fx_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    alpha;
+
+  CacheView
+    *fx_view;
+
+  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 < (long) fx_image->rows; y++)
+  {
+    MagickRealType
+      alpha;
+
+    register IndexPacket
+      *__restrict fx_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
+    id=GetOpenMPThreadId();
+    alpha=0.0;
+    for (x=0; x < (long) fx_image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
+            &alpha,exception);
+          q->red=RoundToQuantum((MagickRealType) QuantumRange*alpha);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
+            &alpha,exception);
+          q->green=RoundToQuantum((MagickRealType) QuantumRange*alpha);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
+            &alpha,exception);
+          q->blue=RoundToQuantum((MagickRealType) QuantumRange*alpha);
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],OpacityChannel,x,y,
+            &alpha,exception);
+          if (image->matte == MagickFalse)
+            q->opacity=RoundToQuantum((MagickRealType) QuantumRange*alpha);
+          else
+            q->opacity=RoundToQuantum((MagickRealType) (QuantumRange-
+              QuantumRange*alpha));
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (fx_image->colorspace == CMYKColorspace))
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y,
+            &alpha,exception);
+          fx_indexes[x]=(IndexPacket) RoundToQuantum((MagickRealType)
+            QuantumRange*alpha);
+        }
+      q++;
+    }
+    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_image->matte=fx_info[0]->matte;
+  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"
+
+  Image
+    *implode_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    radius;
+
+  PointInfo
+    center,
+    scale;
+
+  ResampleFilter
+    **resample_filter;
+
+  CacheView
+    *image_view,
+    *implode_view;
+
+  /*
+    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.opacity != OpaqueOpacity)
+    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;
+  GetMagickPixelPacket(implode_image,&zero);
+  resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
+  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 < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    MagickRealType
+      distance;
+
+    PointInfo
+      delta;
+
+    register IndexPacket
+      *__restrict implode_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    implode_indexes=GetCacheViewAuthenticIndexQueue(implode_view);
+    delta.y=scale.y*(double) (y-center.y);
+    pixel=zero;
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) 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) ResamplePixelColor(resample_filter[id],(double)
+            (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/
+            scale.y+center.y),&pixel);
+          SetPixelPacket(implode_image,&pixel,q,implode_indexes+x);
+        }
+      q++;
+    }
+    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);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  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 unsigned long 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 unsigned long number_frames,ExceptionInfo *exception)
+{
+#define MorphImageTag  "Morph/Image"
+
+  Image
+    *morph_image,
+    *morph_images;
+
+  long
+    y;
+
+  MagickOffsetType
+    scene;
+
+  MagickRealType
+    alpha,
+    beta;
+
+  register const Image
+    *next;
+
+  register long
+    i;
+
+  MagickBooleanType
+    status;
+
+  /*
+    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 < (long) 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) &&
+            (QuantumTick(i,number_frames) != MagickFalse))
+          {
+            status=image->progress_monitor(MorphImageTag,i,number_frames,
+              image->client_data);
+            if (status == MagickFalse)
+              break;
+          }
+      }
+      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 < (long) number_frames; i++)
+    {
+      CacheView
+        *image_view,
+        *morph_view;
+
+      beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0);
+      alpha=1.0-beta;
+      morph_image=ZoomImage(next,(unsigned long) (alpha*next->columns+beta*
+        GetNextImageInList(next)->columns+0.5),(unsigned long) (alpha*
+        next->rows+beta*GetNextImageInList(next)->rows+0.5),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=ZoomImage(GetNextImageInList(next),morph_images->columns,
+        morph_images->rows,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 < (long) morph_images->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const PixelPacket
+          *__restrict p;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) morph_images->columns; x++)
+        {
+          q->red=RoundToQuantum(alpha*q->red+beta*p->red);
+          q->green=RoundToQuantum(alpha*q->green+beta*p->green);
+          q->blue=RoundToQuantum(alpha*q->blue+beta*p->blue);
+          q->opacity=RoundToQuantum(alpha*q->opacity+beta*p->opacity);
+          p++;
+          q++;
+        }
+        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 < (long) 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,
+%        unsigned long attenuate,unsigned long 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 plasmattenuation factor.
+%
+%    o depth: Limit the plasma recursion depth.
+%
+*/
+
+static inline Quantum PlasmaPixel(RandomInfo *random_info,
+  const MagickRealType pixel,const MagickRealType noise)
+{
+  Quantum
+    plasma;
+
+  plasma=RoundToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
+    noise/2.0);
+  return(plasma);
+}
+
+MagickExport MagickBooleanType PlasmaImageProxy(Image *image,
+  RandomInfo *random_info,const SegmentInfo *segment,unsigned long attenuate,
+  unsigned long depth)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    x,
+    x_mid,
+    y,
+    y_mid;
+
+  MagickRealType
+    plasma;
+
+  PixelPacket
+    u,
+    v;
+
+  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=(long) (segment->x1+segment->x2+0.5)/2;
+      y_mid=(long) (segment->y1+segment->y2+0.5)/2;
+      local_info=(*segment);
+      local_info.x2=(double) x_mid;
+      local_info.y2=(double) y_mid;
+      (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
+      local_info=(*segment);
+      local_info.y1=(double) y_mid;
+      local_info.x2=(double) x_mid;
+      (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
+      local_info=(*segment);
+      local_info.x1=(double) x_mid;
+      local_info.y2=(double) y_mid;
+      (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
+      local_info=(*segment);
+      local_info.x1=(double) x_mid;
+      local_info.y1=(double) y_mid;
+      return(PlasmaImageProxy(image,random_info,&local_info,attenuate,depth));
+    }
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  x_mid=(long) (segment->x1+segment->x2+0.5)/2;
+  y_mid=(long) (segment->y1+segment->y2+0.5)/2;
+  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 PixelPacket
+        *__restrict q;
+
+      /*
+        Left pixel.
+      */
+      x=(long) (segment->x1+0.5);
+      (void) GetOneVirtualPixel(image,x,(long) (segment->y1+0.5),&u,exception);
+      (void) GetOneVirtualPixel(image,x,(long) (segment->y2+0.5),&v,exception);
+      q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
+      if (q == (PixelPacket *) NULL)
+        return(MagickTrue);
+      q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
+        plasma);
+      q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
+        plasma);
+      q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
+        plasma);
+      (void) SyncAuthenticPixels(image,exception);
+      if (segment->x1 != segment->x2)
+        {
+          /*
+            Right pixel.
+          */
+          x=(long) (segment->x2+0.5);
+          (void) GetOneVirtualPixel(image,x,(long) (segment->y1+0.5),&u,
+            exception);
+          (void) GetOneVirtualPixel(image,x,(long) (segment->y2+0.5),&v,
+            exception);
+          q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
+          if (q == (PixelPacket *) NULL)
+            return(MagickTrue);
+          q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
+            plasma);
+          q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
+            2.0,plasma);
+          q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
+             plasma);
+          (void) SyncAuthenticPixels(image,exception);
+        }
+    }
+  if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
+    {
+      if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
+        {
+          register PixelPacket
+            *__restrict q;
+
+          /*
+            Bottom pixel.
+          */
+          y=(long) (segment->y2+0.5);
+          (void) GetOneVirtualPixel(image,(long) (segment->x1+0.5),y,&u,
+            exception);
+          (void) GetOneVirtualPixel(image,(long) (segment->x2+0.5),y,&v,
+            exception);
+          q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
+          if (q == (PixelPacket *) NULL)
+            return(MagickTrue);
+          q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
+            plasma);
+          q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
+            2.0,plasma);
+          q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
+            plasma);
+          (void) SyncAuthenticPixels(image,exception);
+        }
+      if (segment->y1 != segment->y2)
+        {
+          register PixelPacket
+            *__restrict q;
+
+          /*
+            Top pixel.
+          */
+          y=(long) (segment->y1+0.5);
+          (void) GetOneVirtualPixel(image,(long) (segment->x1+0.5),y,&u,
+            exception);
+          (void) GetOneVirtualPixel(image,(long) (segment->x2+0.5),y,&v,
+            exception);
+          q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
+          if (q == (PixelPacket *) NULL)
+            return(MagickTrue);
+          q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
+            plasma);
+          q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
+            2.0,plasma);
+          q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
+            plasma);
+          (void) SyncAuthenticPixels(image,exception);
+        }
+    }
+  if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
+    {
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Middle pixel.
+      */
+      x=(long) (segment->x1+0.5);
+      y=(long) (segment->y1+0.5);
+      (void) GetOneVirtualPixel(image,x,y,&u,exception);
+      x=(long) (segment->x2+0.5);
+      y=(long) (segment->y2+0.5);
+      (void) GetOneVirtualPixel(image,x,y,&v,exception);
+      q=QueueAuthenticPixels(image,x_mid,y_mid,1,1,exception);
+      if (q == (PixelPacket *) NULL)
+        return(MagickTrue);
+      q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
+        plasma);
+      q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
+        plasma);
+      q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
+        plasma);
+      (void) SyncAuthenticPixels(image,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,unsigned long attenuate,unsigned long depth)
+{
+  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(),"...");
+  random_info=AcquireRandomInfo();
+  status=PlasmaImageProxy(image,random_info,segment,attenuate,depth);
+  random_info=DestroyRandomInfo(random_info);
+  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;
+
+  long
+    quantum;
+
+  Image
+    *bend_image,
+    *caption_image,
+    *flop_image,
+    *picture_image,
+    *polaroid_image,
+    *rotate_image,
+    *trim_image;
+
+  unsigned long
+    height;
+
+  /*
+    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=(long) 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;
+
+      long
+        count;
+
+      MagickBooleanType
+        status;
+
+      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,&metrics,&caption);
+      status=SetImageExtent(caption_image,image->columns,(unsigned long)
+        ((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) FormatMagickString(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,(long) (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,
+    (long) (-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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R e c o l o r I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RecolorImage() translate, scale, shear, or rotate image colors.  Although
+%  you can use variable sized matrices, typically you use a 5 x 5 for an RGBA
+%  image and a 6x6 for CMYKA.  Populate the last row with normalized values to
+%  translate.
+%
+%  The format of the RecolorImage method is:
+%
+%      Image *RecolorImage(const Image *image,const unsigned long order,
+%        const double *color_matrix,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o order: the number of columns and rows in the recolor matrix.
+%
+%    o color_matrix: An array of double representing the recolor matrix.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *RecolorImage(const Image *image,const unsigned long order,
+  const double *color_matrix,ExceptionInfo *exception)
+{
+#define RecolorImageTag  "Recolor/Image"
+
+  Image
+    *recolor_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  register const double
+    *k;
+
+  CacheView
+    *image_view,
+    *recolor_view;
+
+  /*
+    Initialize 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);
+  recolor_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (recolor_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(recolor_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&recolor_image->exception);
+      recolor_image=DestroyImage(recolor_image);
+      return((Image *) NULL);
+    }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      long
+        u,
+        v;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  Recolor image with %ldx%ld color matrix:",order,order);
+      message=AcquireString("");
+      k=color_matrix;
+      for (v=0; v < (long) order; v++)
+      {
+        *message='\0';
+        (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (long) order; u++)
+        {
+          (void) FormatMagickString(format,MaxTextExtent,"%+f ",*k++);
+          (void) ConcatenateString(&message,format);
+        }
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  /*
+    Recolor image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(image,&zero);
+  k=color_matrix;
+  image_view=AcquireCacheView(image);
+  recolor_view=AcquireCacheView(recolor_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel,
+      recolor_pixel;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register IndexPacket
+      *__restrict recolor_indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(recolor_view,0,y,recolor_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    recolor_indexes=GetCacheViewAuthenticIndexQueue(recolor_view);
+    pixel=zero;
+    recolor_pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,p,indexes,&pixel);
+      SetMagickPixelPacket(recolor_image,p,indexes,&recolor_pixel);
+      switch (order)
+      {
+        case 0:
+          break;
+        case 1:
+        {
+          recolor_pixel.red=k[0]*pixel.red;
+          break;
+        }
+        case 2:
+        {
+          recolor_pixel.red=k[0]*pixel.red+k[1]*pixel.green;
+          recolor_pixel.green=k[2]*pixel.red+k[3]*pixel.green;
+          break;
+        }
+        case 3:
+        {
+          recolor_pixel.red=k[0]*pixel.red+k[1]*pixel.green+k[2]*pixel.blue;
+          recolor_pixel.green=k[3]*pixel.red+k[4]*pixel.green+k[5]*pixel.blue;
+          recolor_pixel.blue=k[6]*pixel.red+k[7]*pixel.green+k[8]*pixel.blue;
+          break;
+        }
+        case 4:
+        {
+          recolor_pixel.red=k[0]*pixel.red+k[1]*pixel.green+k[2]*pixel.blue+
+            k[12]*QuantumRange;
+          recolor_pixel.green=k[4]*pixel.red+k[5]*pixel.green+k[6]*pixel.blue+
+            k[13]*QuantumRange;
+          recolor_pixel.blue=k[8]*pixel.red+k[9]*pixel.green+k[10]*pixel.blue+
+            k[14]*QuantumRange;
+          break;
+        }
+        case 5:
+        {
+          recolor_pixel.red=k[0]*pixel.red+k[1]*pixel.green+k[2]*pixel.blue+
+            k[3]*(QuantumRange-pixel.opacity)+k[20]*QuantumRange;
+          recolor_pixel.green=k[5]*pixel.red+k[6]*pixel.green+k[7]*pixel.blue+
+            k[8]*(QuantumRange-pixel.opacity)+k[21]*QuantumRange;
+          recolor_pixel.blue=k[10]*pixel.red+k[11]*pixel.green+k[12]*pixel.blue+
+            k[13]*(QuantumRange-pixel.opacity)+k[22]*QuantumRange;
+          recolor_pixel.opacity=(MagickRealType) QuantumRange-(k[15]*pixel.red+
+            k[16]*pixel.green+k[17]*pixel.blue+k[18]*(QuantumRange-
+            pixel.opacity)+k[23]*QuantumRange);
+          break;
+        }
+        default:
+        {
+          recolor_pixel.red=k[0]*pixel.red+k[1]*pixel.green+k[2]*pixel.blue+
+            k[3]*pixel.index+k[4]*((Quantum) QuantumRange-pixel.opacity)+
+            k[30]*QuantumRange;
+          recolor_pixel.green=k[6]*pixel.red+k[7]*pixel.green+k[8]*pixel.blue+
+            k[9]*pixel.index+k[10]*((Quantum) QuantumRange-pixel.opacity)+
+            k[31]*QuantumRange;
+          recolor_pixel.blue=k[12]*pixel.red+k[13]*pixel.green+k[14]*pixel.blue+
+            k[15]*pixel.index+k[16]*((Quantum) QuantumRange-pixel.opacity)+
+            k[32]*QuantumRange;
+          if (image->colorspace == CMYKColorspace)
+            recolor_pixel.index=k[18]*pixel.red+k[19]*pixel.green+k[20]*
+              pixel.blue+k[21]*pixel.index+k[22]*((Quantum) QuantumRange-
+              pixel.opacity)+k[33]*QuantumRange;
+          recolor_pixel.opacity=(MagickRealType) QuantumRange-(k[24]*pixel.red+
+            k[25]*pixel.green+k[26]*pixel.blue+k[27]*pixel.index+k[28]*
+            (QuantumRange-pixel.opacity)+k[34]*QuantumRange);
+          break;
+        }
+      }
+      q->red=RoundToQuantum(recolor_pixel.red);
+      q->green=RoundToQuantum(recolor_pixel.green);
+      q->blue=RoundToQuantum(recolor_pixel.blue);
+      q->opacity=RoundToQuantum(recolor_pixel.opacity);
+      if (image->colorspace == CMYKColorspace)
+        recolor_indexes[x]=RoundToQuantum(recolor_pixel.index);
+      p++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(recolor_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RecolorImage)
+#endif
+        proceed=SetImageProgress(image,RecolorImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  recolor_view=DestroyCacheView(recolor_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    recolor_image=DestroyImage(recolor_image);
+  return(recolor_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"
+
+  Image
+    *sepia_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view,
+    *sepia_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickRealType
+        intensity,
+        tone;
+
+      intensity=(MagickRealType) PixelIntensityToQuantum(p);
+      tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
+        (MagickRealType) QuantumRange-threshold;
+      q->red=RoundToQuantum(tone);
+      tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
+        intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
+      q->green=RoundToQuantum(tone);
+      tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
+      q->blue=RoundToQuantum(tone);
+      tone=threshold/7.0;
+      if ((MagickRealType) q->green < tone)
+        q->green=RoundToQuantum(tone);
+      if ((MagickRealType) q->blue < tone)
+        q->blue=RoundToQuantum(tone);
+      p++;
+      q++;
+    }
+    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 long x_offset,const long 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 long x_offset,const long y_offset,
+  ExceptionInfo *exception)
+{
+#define ShadowImageTag  "Shadow/Image"
+
+  Image
+    *border_image,
+    *clone_image,
+    *shadow_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    border_info;
+
+  CacheView
+    *image_view;
+
+  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=(unsigned long) (2.0*sigma+0.5);
+  border_info.height=(unsigned long) (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;
+  image_view=AcquireCacheView(border_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) border_image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) border_image->columns; x++)
+    {
+      q->red=border_image->background_color.red;
+      q->green=border_image->background_color.green;
+      q->blue=border_image->background_color.blue;
+      if (border_image->matte == MagickFalse)
+        q->opacity=border_image->background_color.opacity;
+      else
+        q->opacity=RoundToQuantum((MagickRealType) (QuantumRange-(QuantumRange-
+          q->opacity)*opacity/100.0));
+      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_ShadowImage)
+#endif
+        proceed=SetImageProgress(image,ShadowImageTag,progress++,
+          border_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_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-(long) border_info.width;
+  shadow_image->page.height+=y_offset-(long) border_info.height;
+  shadow_image->page.x+=x_offset-(long) border_info.width;
+  shadow_image->page.y+=y_offset-(long) 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)
+{
+  Image
+    *blend_image,
+    *blur_image,
+    *dodge_image,
+    *random_image,
+    *sketch_image;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  RandomInfo
+    *random_info;
+
+  CacheView
+    *random_view;
+
+  /*
+    Sketch image.
+  */
+  random_image=CloneImage(image,image->columns << 1,image->rows << 1,
+    MagickTrue,exception);
+  if (random_image == (Image *) NULL)
+    return((Image *) NULL);
+  status=MagickTrue;
+  GetMagickPixelPacket(random_image,&zero);
+  random_info=AcquireRandomInfo();
+  random_view=AcquireCacheView(random_image);
+  for (y=0; y < (long) random_image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(random_view);
+    pixel=zero;
+    for (x=0; x < (long) random_image->columns; x++)
+    {
+      pixel.red=(MagickRealType) (QuantumRange*
+        GetPseudoRandomValue(random_info));
+      pixel.green=pixel.red;
+      pixel.blue=pixel.red;
+      if (image->colorspace == CMYKColorspace)
+        pixel.index=pixel.red;
+      SetPixelPacket(random_image,&pixel,q,indexes+x);
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+  }
+  random_view=DestroyCacheView(random_view);
+  random_info=DestroyRandomInfo(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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  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 long
+        i;
+
+      /*
+        Solarize colormap.
+      */
+      for (i=0; i < (long) 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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((MagickRealType) q->red > threshold)
+        q->red=(Quantum) QuantumRange-q->red;
+      if ((MagickRealType) q->green > threshold)
+        q->green=(Quantum) QuantumRange-q->green;
+      if ((MagickRealType) q->blue > threshold)
+        q->blue=(Quantum) QuantumRange-q->blue;
+      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_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) ((((unsigned long) (alpha) >> (unsigned long) \
+  (i)) & 0x01) != 0)
+#define SetBit(alpha,i,set) (alpha)=(Quantum) ((set) ? (unsigned long) (alpha) \
+  | (1UL << (unsigned long) (i)) : (unsigned long) (alpha) & \
+  ~(1UL << (unsigned long) (i)))
+#define SteganoImageTag  "Stegano/Image"
+
+  Image
+    *stegano_image;
+
+  int
+    c;
+
+  long
+    i,
+    j,
+    k,
+    y;
+
+  MagickBooleanType
+    status;
+
+  PixelPacket
+    pixel;
+
+  register long
+    x;
+
+  register PixelPacket
+    *q;
+
+  unsigned long
+    depth;
+
+  /*
+    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);
+  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;
+  for (i=(long) depth-1; (i >= 0) && (j < (long) depth); i--)
+  {
+    for (y=0; (y < (long) watermark->rows) && (j < (long) depth); y++)
+    {
+      for (x=0; (x < (long) watermark->columns) && (j < (long) depth); x++)
+      {
+        (void) GetOneVirtualPixel(watermark,x,y,&pixel,exception);
+        if ((k/(long) stegano_image->columns) >= (long) stegano_image->rows)
+          break;
+        q=GetAuthenticPixels(stegano_image,k % (long) stegano_image->columns,
+          k/(long) stegano_image->columns,1,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        switch (c)
+        {
+          case 0:
+          {
+            SetBit(q->red,j,GetBit(PixelIntensityToQuantum(&pixel),i));
+            break;
+          }
+          case 1:
+          {
+            SetBit(q->green,j,GetBit(PixelIntensityToQuantum(&pixel),i));
+            break;
+          }
+          case 2:
+          {
+            SetBit(q->blue,j,GetBit(PixelIntensityToQuantum(&pixel),i));
+            break;
+          }
+        }
+        if (SyncAuthenticPixels(stegano_image,exception) == MagickFalse)
+          break;
+        c++;
+        if (c == 3)
+          c=0;
+        k++;
+        if (k == (long) (stegano_image->columns*stegano_image->columns))
+          k=0;
+        if (k == image->offset)
+          j++;
+      }
+    }
+    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
+        (QuantumTick((MagickOffsetType) depth-i,depth) != MagickFalse))
+      {
+        status=image->progress_monitor(SteganoImageTag,(MagickOffsetType) depth-
+          i,depth,image->client_data);
+        if (status == MagickFalse)
+          break;
+      }
+  }
+  if (stegano_image->storage_class == PseudoClass)
+    (void) SyncImage(stegano_image);
+  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 long x_offset,const long 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 long x_offset,const long y_offset,
+  ExceptionInfo *exception)
+{
+#define StereoImageTag  "Stereo/Image"
+
+  const Image
+    *image;
+
+  Image
+    *stereo_image;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  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.
+  */
+  for (y=0; y < (long) stereo_image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL) ||
+        (r == (PixelPacket *) NULL))
+      break;
+    for (x=0; x < (long) stereo_image->columns; x++)
+    {
+      r->red=p->red;
+      r->green=q->green;
+      r->blue=q->blue;
+      r->opacity=(Quantum) ((p->opacity+q->opacity)/2);
+      p++;
+      q++;
+      r++;
+    }
+    if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
+      break;
+    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
+        (QuantumTick(y,image->rows) != MagickFalse))
+      {
+        status=image->progress_monitor(StereoImageTag,y,stereo_image->rows,
+          stereo_image->client_data);
+        if (status == MagickFalse)
+          break;
+      }
+  }
+  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"
+
+  Image
+    *swirl_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    radius;
+
+  PointInfo
+    center,
+    scale;
+
+  ResampleFilter
+    **resample_filter;
+
+  CacheView
+    *image_view,
+    *swirl_view;
+
+  /*
+    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.opacity != OpaqueOpacity)
+    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;
+  GetMagickPixelPacket(swirl_image,&zero);
+  resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
+  image_view=AcquireCacheView(image);
+  swirl_view=AcquireCacheView(swirl_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    MagickRealType
+      distance;
+
+    PointInfo
+      delta;
+
+    register IndexPacket
+      *__restrict swirl_indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    swirl_indexes=GetCacheViewAuthenticIndexQueue(swirl_view);
+    delta.y=scale.y*(double) (y-center.y);
+    pixel=zero;
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) 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) ResamplePixelColor(resample_filter[id],(double) ((cosine*
+            delta.x-sine*delta.y)/scale.x+center.x),(double) ((sine*delta.x+
+            cosine*delta.y)/scale.y+center.y),&pixel);
+          SetPixelPacket(swirl_image,&pixel,q,swirl_indexes+x);
+        }
+      q++;
+    }
+    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);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  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"
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *tint_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  MagickPixelPacket
+    color_vector,
+    pixel;
+
+  CacheView
+    *image_view,
+    *tint_view;
+
+  /*
+    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.opacity=geometry_info.psi;
+  else
+    pixel.opacity=(MagickRealType) OpaqueOpacity;
+  color_vector.red=(MagickRealType) (pixel.red*tint.red/100.0-
+    PixelIntensity(&tint));
+  color_vector.green=(MagickRealType) (pixel.green*tint.green/100.0-
+    PixelIntensity(&tint));
+  color_vector.blue=(MagickRealType) (pixel.blue*tint.blue/100.0-
+    PixelIntensity(&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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        weight;
+
+      weight=QuantumScale*p->red-0.5;
+      pixel.red=(MagickRealType) p->red+color_vector.red*(1.0-(4.0*
+        (weight*weight)));
+      q->red=RoundToQuantum(pixel.red);
+      weight=QuantumScale*p->green-0.5;
+      pixel.green=(MagickRealType) p->green+color_vector.green*(1.0-(4.0*
+        (weight*weight)));
+      q->green=RoundToQuantum(pixel.green);
+      weight=QuantumScale*p->blue-0.5;
+      pixel.blue=(MagickRealType) p->blue+color_vector.blue*(1.0-(4.0*
+        (weight*weight)));
+      q->blue=RoundToQuantum(pixel.blue);
+      q->opacity=p->opacity;
+      p++;
+      q++;
+    }
+    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 long x,const long 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 long x,const long 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) FormatMagickString(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"
+
+  Image
+    *wave_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    *sine_map;
+
+  register long
+    i;
+
+  ResampleFilter
+    **resample_filter;
+
+  CacheView
+    *wave_view;
+
+  /*
+    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,(unsigned long) (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.opacity != OpaqueOpacity)
+    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 < (long) wave_image->columns; i++)
+    sine_map[i]=fabs(amplitude)+amplitude*sin((2*MagickPI*i)/wave_length);
+  /*
+    Wave image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(wave_image,&zero);
+  resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
+  wave_view=AcquireCacheView(wave_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) wave_image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(wave_view);
+    pixel=zero;
+    id=GetOpenMPThreadId();
+    (void) SetResampleFilterVirtualPixelMethod(resample_filter[id],
+      BackgroundVirtualPixelMethod);
+    for (x=0; x < (long) wave_image->columns; x++)
+    {
+      (void) ResamplePixelColor(resample_filter[id],(double) x,(double) (y-
+        sine_map[x]),&pixel);
+      SetPixelPacket(wave_image,&pixel,q,indexes+x);
+      q++;
+    }
+    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);
+  resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+  sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
+  if (status == MagickFalse)
+    wave_image=DestroyImage(wave_image);
+  return(wave_image);
+}
diff --git a/magick/fx.h b/magick/fx.h
new file mode 100644
index 0000000..c017ad5
--- /dev/null
+++ b/magick/fx.h
@@ -0,0 +1,128 @@
+/*
+  Copyright 1999-2009 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 "magick/draw.h"
+
+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
+} MagickEvaluateOperator;
+
+typedef enum
+{
+  UndefinedFunction,
+  PolynomialFunction,
+  SinusoidFunction,
+  ArcsinFunction,
+  ArctanFunction
+} MagickFunction;
+
+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 *),
+  *ConvolveImage(const Image *,const unsigned long,const double *,
+    ExceptionInfo *),
+  *ConvolveImageChannel(const Image *,const ChannelType,const unsigned long,
+    const double *,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 unsigned long,ExceptionInfo *),
+  *PolaroidImage(const Image *,const DrawInfo *,const double,ExceptionInfo *),
+  *RecolorImage(const Image *,const unsigned long,const double *,
+    ExceptionInfo *),
+  *SepiaToneImage(const Image *,const double,ExceptionInfo *),
+  *ShadowImage(const Image *,const double,const double,const long,const long,
+    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 long,const long,
+     ExceptionInfo *),
+  *SwirlImage(const Image *,double,ExceptionInfo *),
+  *TintImage(const Image *,const char *,const PixelPacket,ExceptionInfo *),
+  *VignetteImage(const Image *,const double,const double,const long,
+    const long,ExceptionInfo *),
+  *WaveImage(const Image *,const double,const double,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 unsigned long,const double *,
+    ExceptionInfo *),
+  FunctionImageChannel(Image *,const ChannelType,const MagickFunction,
+    const unsigned long,const double *,ExceptionInfo *),
+  PlasmaImage(Image *,const SegmentInfo *,unsigned long,unsigned long),
+  SolarizeImage(Image *,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/gem.c b/magick/gem.c
new file mode 100644
index 0000000..821a1e5
--- /dev/null
+++ b/magick/gem.c
@@ -0,0 +1,824 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                              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-2009 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 "magick/studio.h"
+#include "magick/color-private.h"
+#include "magick/draw.h"
+#include "magick/gem.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/resize.h"
+#include "magick/transform.h"
+#include "magick/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=RoundToQuantum((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=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*t);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*p);
+      break;
+    }
+    case 1:
+    {
+      *red=RoundToQuantum((MagickRealType) QuantumRange*q);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*p);
+      break;
+    }
+    case 2:
+    {
+      *red=RoundToQuantum((MagickRealType) QuantumRange*p);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*t);
+      break;
+    }
+    case 3:
+    {
+      *red=RoundToQuantum((MagickRealType) QuantumRange*p);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*q);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      break;
+    }
+    case 4:
+    {
+      *red=RoundToQuantum((MagickRealType) QuantumRange*t);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*p);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      break;
+    }
+    case 5:
+    {
+      *red=RoundToQuantum((MagickRealType) QuantumRange*brightness);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*p);
+      *blue=RoundToQuantum((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=RoundToQuantum((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=RoundToQuantum((MagickRealType) QuantumRange*r);
+  *green=RoundToQuantum((MagickRealType) QuantumRange*g);
+  *blue=RoundToQuantum((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 long
+    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=RoundToQuantum((MagickRealType) QuantumRange*v);
+      *green=RoundToQuantum((MagickRealType) QuantumRange*v);
+      *blue=RoundToQuantum((MagickRealType) QuantumRange*v);
+      return;
+    }
+  i=(long) 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=RoundToQuantum((MagickRealType) QuantumRange*r);
+  *green=RoundToQuantum((MagickRealType) QuantumRange*g);
+  *blue=RoundToQuantum((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)
+{
+  MagickRealType
+    f,
+    v,
+    w;
+
+  register long
+    i;
+
+  /*
+    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() 
+%
+%  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  ScaleCharToQuantum((unsigned char) (attenuate*4.0+0.5))
+#define SigmaGaussian  ScaleCharToQuantum((unsigned char) (attenuate*4.0+0.5))
+#define SigmaImpulse  (attenuate*0.10)
+#define SigmaLaplacian ScaleCharToQuantum((unsigned char) (attenuate*10.0+0.5))
+#define SigmaMultiplicativeGaussian \
+  ScaleCharToQuantum((unsigned char) (attenuate*1.0+0.5))
+#define SigmaPoisson  (attenuate*0.05)
+#define TauGaussian  ScaleCharToQuantum((unsigned char) (attenuate*20.0+0.5))
+
+  MagickRealType
+    alpha,
+    beta,
+    noise,
+    sigma;
+
+  alpha=GetPseudoRandomValue(random_info);
+  if (alpha == 0.0)
+    alpha=1.0;
+  switch (noise_type)
+  {
+    case UniformNoise:
+    default:
+    {
+      noise=(MagickRealType) pixel+SigmaUniform*(alpha-0.5);
+      break;
+    }
+    case GaussianNoise:
+    {
+      MagickRealType
+        tau;
+
+      beta=GetPseudoRandomValue(random_info);
+      sigma=sqrt(-2.0*log((double) alpha))*cos((double) (2.0*MagickPI*beta));
+      tau=sqrt(-2.0*log((double) alpha))*sin((double) (2.0*MagickPI*beta));
+      noise=(MagickRealType) pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
+        TauGaussian*tau;
+      break;
+    }
+    case MultiplicativeGaussianNoise:
+    {
+      if (alpha <= NoiseEpsilon)
+        sigma=(MagickRealType) QuantumRange;
+      else
+        sigma=sqrt(-2.0*log((double) alpha));
+      beta=GetPseudoRandomValue(random_info);
+      noise=(MagickRealType) 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=(MagickRealType) QuantumRange;
+         else
+           noise=(MagickRealType) pixel;
+      break;
+    }
+    case LaplacianNoise:
+    {
+      if (alpha <= 0.5)
+        {
+          if (alpha <= NoiseEpsilon)
+            noise=(MagickRealType) pixel-(MagickRealType) QuantumRange;
+          else
+            noise=(MagickRealType) pixel+ScaleCharToQuantum((unsigned char)
+              (SigmaLaplacian*log((double) (2.0*alpha))+0.5));
+          break;
+        }
+      beta=1.0-alpha;
+      if (beta <= (0.5*NoiseEpsilon))
+        noise=(MagickRealType) (pixel+QuantumRange);
+      else
+        noise=(MagickRealType) pixel-ScaleCharToQuantum((unsigned char)
+          (SigmaLaplacian*log((double) (2.0*beta))+0.5));
+      break;
+    }
+    case PoissonNoise:
+    {
+      MagickRealType
+        poisson;
+
+      register long
+        i;
+
+      poisson=exp(-SigmaPoisson*(double) ScaleQuantumToChar(pixel));
+      for (i=0; alpha > poisson; i++)
+      {
+        beta=GetPseudoRandomValue(random_info);
+        alpha*=beta;
+      }
+      noise=(MagickRealType) ScaleCharToQuantum((unsigned char)
+        (i/SigmaPoisson));
+      break;
+    }
+    case RandomNoise:
+    {
+      noise=(MagickRealType) QuantumRange*GetPseudoRandomValue(random_info);
+      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:
+%
+%      unsigned long 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 unsigned long GetOptimalKernelWidth1D(const double radius,
+  const double sigma)
+{
+  long
+    width;
+
+  MagickRealType
+    normalize,
+    value;
+
+  register long
+    u;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (radius > 0.0)
+    return((unsigned long) (2.0*ceil(radius)+1.0));
+  if (fabs(sigma) <= MagickEpsilon)
+    return(1);
+  for (width=5; ; )
+  {
+    normalize=0.0;
+    for (u=(-width/2); u <= (width/2); u++)
+      normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
+    u=width/2;
+    value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
+    if ((long) (QuantumRange*value) <= 0L)
+      break;
+    width+=2;
+  }
+  return((unsigned long) (width-2));
+}
+
+MagickExport unsigned long GetOptimalKernelWidth2D(const double radius,
+  const double sigma)
+{
+
+  long
+    width;
+
+  MagickRealType
+    alpha,
+    normalize,
+    value;
+
+  register long
+    u,
+    v;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (radius > 0.0)
+    return((unsigned long) (2.0*ceil(radius)+1.0));
+  if (fabs(sigma) <= MagickEpsilon)
+    return(1);
+  for (width=5; ; )
+  {
+    normalize=0.0;
+    for (v=(-width/2); v <= (width/2); v++)
+    {
+      for (u=(-width/2); u <= (width/2); u++)
+      {
+        alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
+        normalize+=alpha/(2.0*MagickPI*sigma*sigma);
+      }
+    }
+    v=width/2;
+    value=exp(-((double) v*v)/(2.0*sigma*sigma))/normalize;
+    if ((long) (QuantumRange*value) <= 0L)
+      break;
+    width+=2;
+  }
+  return((unsigned long) (width-2));
+}
+
+MagickExport unsigned long  GetOptimalKernelWidth(const double radius,
+  const double sigma)
+{
+  return(GetOptimalKernelWidth1D(radius,sigma));
+}
diff --git a/magick/gem.h b/magick/gem.h
new file mode 100644
index 0000000..f16c4dc
--- /dev/null
+++ b/magick/gem.h
@@ -0,0 +1,56 @@
+/*
+  Copyright 1999-2009 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 <magick/fx.h>
+#include <magick/random_.h>
+
+extern MagickExport double
+  ExpandAffine(const AffineMatrix *),
+  GenerateDifferentialNoise(RandomInfo *,const Quantum,const NoiseType,
+    const MagickRealType);
+
+extern MagickExport unsigned long
+  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/magick/geometry.c b/magick/geometry.c
new file mode 100644
index 0000000..6ff1bba
--- /dev/null
+++ b/magick/geometry.c
@@ -0,0 +1,1390 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/memory_.h"
+#include "magick/string_.h"
+#include "magick/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,long *x,long *y,
+%        unsigned long *width,unsigned long *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,long *x,long *y,
+  unsigned long *width,unsigned long *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)
+    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 (*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=strtod(p,&q);
+  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=(unsigned long) strtol(p,&p,10);
+      else
+        *width=(unsigned long) floor(strtod(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=(unsigned long) floor(strtod(p,&p)+0.5);
+          if (p != q)
+            flags|=HeightValue;
+        }
+    }
+  if ((*p == '+') || (*p == '-'))
+    {
+      /*
+        Parse x value.
+      */
+      if (*p == '-')
+        flags|=XNegative;
+      q=p;
+      *x=(long) ceil(strtod(p,&p)-0.5);
+      if (p != q)
+        flags|=XValue;
+      if ((*p == '+') || (*p == '-'))
+        {
+          /*
+            Parse y value.
+          */
+          if (*p == '-')
+            flags|=YNegative;
+          q=p;
+          *y=(long) ceil(strtod(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 long
+    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 unsigned long width,
+%        const unsigned long 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 unsigned long width,
+  const unsigned long 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=(long) (width-region->width-region->x);
+      break;
+    }
+    case NorthGravity:
+    case SouthGravity:
+    case CenterGravity:
+    case StaticGravity:
+    {
+      region->x+=(long) (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=(long) (height-region->height-region->y);
+      break;
+    }
+    case EastGravity:
+    case WestGravity:
+    case CenterGravity:
+    case StaticGravity:
+    {
+      region->y+=(long) (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=strtod(geometry,&p);
+  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.
+%
+%  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 (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 the geometry
+%  string.
+%
+%  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 (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 long
+    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=atof(token); break;
+      case 1: affine_matrix->rx=atof(token); break;
+      case 2: affine_matrix->ry=atof(token); break;
+      case 3: affine_matrix->sy=atof(token); break;
+      case 4: affine_matrix->tx=atof(token); flags|=XValue; break;
+      case 5: affine_matrix->ty=atof(token); 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, there are flags to
+%  report any meta characters (%, !, <, or >).
+%
+%  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.
+%
+%    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)
+    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 (*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=strtod(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=strtod(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=strtod(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=strtod(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=strtod(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=strtod(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 image dimensions and its gravity.
+%
+%  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 (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;
+
+  unsigned long
+    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.
+      */
+      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=(unsigned long) ((scale.x*image->columns/100.0)+0.5);
+      region_info->height=(unsigned long) ((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 ~.
+%
+%  The format of the ParseMetaGeometry method is:
+%
+%      MagickStatusType ParseMetaGeometry(const char *geometry,long *x,long *y,
+%        unsigned long *width,unsigned long *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.
+%
+*/
+
+static inline unsigned long MagickMax(const unsigned long x,
+  const unsigned long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,long *x,
+  long *y,unsigned long *width,unsigned long *height)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  unsigned long
+    former_height,
+    former_width;
+
+  /*
+    Ensure the image geometry is valid.
+  */
+  assert(x != (long *) NULL);
+  assert(y != (long *) NULL);
+  assert(width != (unsigned long *) NULL);
+  assert(height != (unsigned long *) 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=(unsigned long) (scale.x*former_width/100.0+0.5);
+      if (*width == 0)
+        *width=1;
+      *height=(unsigned long) (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((unsigned long) (scale_factor*former_width+0.5),1UL);
+      *height=MagickMax((unsigned long) (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=(unsigned long) (former_width/(distance/sqrt((double) area)));
+          *height=(unsigned long) (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 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 (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.
+%
+%  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 (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/magick/geometry.h b/magick/geometry.h
new file mode 100644
index 0000000..043b328
--- /dev/null
+++ b/magick/geometry.h
@@ -0,0 +1,151 @@
+/*
+  Copyright 1999-2009 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,
+  AspectValue = 0x2000,
+  LessValue = 0x4000,
+  GreaterValue = 0x8000,
+  MinimumValue = 0x10000,
+  AreaValue = 0x20000,
+  DecimalValue = 0x40000,
+#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 _RectangleInfo
+{
+  unsigned long
+    width,
+    height;
+
+  long
+    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 *,long *,long *,unsigned long *,unsigned long *),
+  ParseAbsoluteGeometry(const char *,RectangleInfo *),
+  ParseAffineGeometry(const char *,AffineMatrix *,ExceptionInfo *),
+  ParseGeometry(const char *,GeometryInfo *),
+  ParseGravityGeometry(const Image *,const char *,RectangleInfo *,
+    ExceptionInfo *),
+  ParseMetaGeometry(const char *,long *,long *,unsigned long *,unsigned long *),
+  ParsePageGeometry(const Image *,const char *,RectangleInfo *,ExceptionInfo *),
+  ParseRegionGeometry(const Image *,const char *,RectangleInfo *,
+    ExceptionInfo *);
+
+extern MagickExport void
+  GravityAdjustGeometry(const unsigned long,const unsigned long,
+    const GravityType,RectangleInfo *),
+  SetGeometry(const Image *,RectangleInfo *),
+  SetGeometryInfo(GeometryInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/hashmap.c b/magick/hashmap.c
new file mode 100644
index 0000000..33d3d7f
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/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
+{
+  unsigned long
+    capacity,
+    elements;
+
+  ElementInfo
+    *head,
+    *tail,
+    *next;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    signature;
+};
+
+struct _HashmapInfo
+{
+  size_t
+    (*hash)(const void *);
+
+  MagickBooleanType
+    (*compare)(const void *,const void *);
+
+  void
+    *(*relinquish_key)(void *),
+    *(*relinquish_value)(void *);
+
+  unsigned long
+    capacity,
+    entries,
+    next;
+
+  MagickBooleanType
+    head_of_list;
+
+  LinkedListInfo
+    **map;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    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;
+  (void) 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++;
+  (void) 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(),"...");
+  (void) 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;
+  (void) UnlockSemaphoreInfo(list_info->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e H a s h m a p S t r i n g                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Specify the CompareHashmapString() method in NewHashmap() to find 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                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Specify the CompareHashmapStringInfo() method in NewHashmap() to find 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 long
+    i;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  (void) LockSemaphoreInfo(hashmap_info->semaphore);
+  for (i=0; i < (long) 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);
+  (void) 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(),"...");
+  (void) 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);
+  (void) 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);
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  value=list_info->tail->value;
+  (void) 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(),"...");
+  (void) 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;
+            (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+            return(key);
+          }
+        hashmap_info->head_of_list=MagickFalse;
+      }
+    hashmap_info->next++;
+  }
+  (void) 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(),"...");
+  (void) 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;
+            (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+            return(value);
+          }
+        hashmap_info->head_of_list=MagickFalse;
+      }
+    hashmap_info->next++;
+  }
+  (void) 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(),"...");
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  if (list_info->next == (ElementInfo *) NULL)
+    {
+      (void) UnlockSemaphoreInfo(list_info->semaphore);
+      return((void *) NULL);
+    }
+  value=list_info->next->value;
+  list_info->next=list_info->next->next;
+  (void) 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:
+%
+%      unsigned long GetNumberOfEntriesInHashmap(const HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport unsigned long 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:
+%
+%      unsigned long GetNumberOfElementsInLinkedList(
+%        const LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport unsigned long 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);
+  (void) 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;
+                (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+                return(value);
+              }
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      }
+    }
+  (void) 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 unsigned long 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 unsigned long index)
+{
+  register ElementInfo
+    *next;
+
+  register long
+    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);
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  if (index == 0)
+    {
+      value=list_info->head->value;
+      (void) UnlockSemaphoreInfo(list_info->semaphore);
+      return(value);
+    }
+  if (index == (list_info->elements-1))
+    {
+      value=list_info->tail->value;
+      (void) UnlockSemaphoreInfo(list_info->semaphore);
+      return(value);
+    }
+  next=list_info->head;
+  for (i=0; i < (long) index; i++)
+    next=next->next;
+  value=next->value;
+  (void) UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H a s h P o i n t e r T y p e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Specify the HashPointerType() method in NewHashmap() to find 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                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Specify the HashStringType() method in NewHashmap() to find 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 long
+    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 long
+    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 unsigned long 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 unsigned long index,const void *value)
+{
+  register ElementInfo
+    *next;
+
+  register long
+    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;
+  (void) 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 < (long) 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++;
+  (void) 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 long
+    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;
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  next->next=list_info->head;
+  while (next->next != (ElementInfo *) NULL)
+  {
+    i=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++;
+  (void) 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 long
+    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);
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  next=list_info->head;
+  for (i=0; next != (ElementInfo *) NULL; i++)
+  {
+    array[i]=next->value;
+    next=next->next;
+  }
+  (void) 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 unsigned long 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 unsigned long 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 unsigned long capacity)
+%
+%  A description of each parameter follows:
+%
+%    o capacity: the maximum number of elements in the list.
+%
+*/
+MagickExport LinkedListInfo *NewLinkedList(const unsigned long 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 ? (unsigned long) (~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 unsigned long
+    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 long
+    i;
+
+  unsigned long
+    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 < (long) hashmap_info->capacity; i++)
+  {
+    list_info=hashmap_info->map[i];
+    if (list_info == (LinkedListInfo *) NULL)
+      continue;
+    (void) 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);
+    (void) 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 unsigned long
+    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);
+  (void) 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);
+      (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+      return(MagickFalse);
+    }
+  if (list_info->elements >= (hashmap_info->capacity-1))
+    if (IncreaseHashmapCapacity(hashmap_info) == MagickFalse)
+      {
+        (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+        return(MagickFalse);
+      }
+  hashmap_info->entries++;
+  (void) 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);
+  (void) 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)
+        {
+          (void) 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--;
+  (void) 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 unsigned long 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 unsigned long index)
+{
+  ElementInfo
+    *next;
+
+  register long
+    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);
+  (void) 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 < (long) 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--;
+  (void) 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 unsigned long
+    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);
+  (void) 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)
+                  {
+                    (void) 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--;
+                (void) UnlockSemaphoreInfo(hashmap_info->semaphore);
+                return(value);
+              }
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      }
+    }
+  (void) 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);
+  (void) 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--;
+  (void) 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(),"...");
+  (void) LockSemaphoreInfo(hashmap_info->semaphore);
+  hashmap_info->next=0;
+  hashmap_info->head_of_list=MagickFalse;
+  (void) 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(),"...");
+  (void) LockSemaphoreInfo(list_info->semaphore);
+  list_info->next=list_info->head;
+  (void) UnlockSemaphoreInfo(list_info->semaphore);
+}
diff --git a/magick/hashmap.h b/magick/hashmap.h
new file mode 100644
index 0000000..8154e69
--- /dev/null
+++ b/magick/hashmap.h
@@ -0,0 +1,86 @@
+/*
+  Copyright 1999-2009 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 unsigned long,size_t (*)(const void *),
+    MagickBooleanType (*)(const void *,const void *),void *(*)(void *),
+    void *(*)(void *));
+
+extern MagickExport LinkedListInfo
+  *DestroyLinkedList(LinkedListInfo *,void *(*)(void *)),
+  *NewLinkedList(const unsigned long);
+
+extern MagickExport MagickBooleanType
+  AppendValueToLinkedList(LinkedListInfo *,const void *),
+  CompareHashmapString(const void *,const void *),
+  CompareHashmapStringInfo(const void *,const void *),
+  InsertValueInLinkedList(LinkedListInfo *,const unsigned long,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
+  HashPointerType(const void *),
+  HashStringType(const void *),
+  HashStringInfoType(const void *);
+
+extern MagickExport unsigned long
+  GetNumberOfElementsInLinkedList(const LinkedListInfo *),
+  GetNumberOfEntriesInHashmap(const HashmapInfo *);
+
+extern MagickExport void
+  ClearLinkedList(LinkedListInfo *,void *(*)(void *)),
+  *GetLastValueInLinkedList(LinkedListInfo *),
+  *GetNextKeyInHashmap(HashmapInfo *),
+  *GetNextValueInHashmap(HashmapInfo *),
+  *GetNextValueInLinkedList(LinkedListInfo *),
+  *GetValueFromHashmap(HashmapInfo *,const void *),
+  *GetValueFromLinkedList(LinkedListInfo *,const unsigned long),
+  *RemoveElementByValueFromLinkedList(LinkedListInfo *,const void *),
+  *RemoveElementFromLinkedList(LinkedListInfo *,const unsigned long),
+  *RemoveEntryFromHashmap(HashmapInfo *,const void *),
+  *RemoveLastElementFromLinkedList(LinkedListInfo *),
+  ResetHashmapIterator(HashmapInfo *),
+  ResetLinkedListIterator(LinkedListInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/histogram.c b/magick/histogram.c
new file mode 100644
index 0000000..408ce2e
--- /dev/null
+++ b/magick/histogram.c
@@ -0,0 +1,164 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%      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-2009 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 "magick/studio.h"
+#include "magick/cache-view.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/histogram.h"
+#include "magick/image.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/prepress.h"
+#include "magick/registry.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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 equivelent 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).
+%
+%  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;
+
+  if ((channel & SyncChannels) != 0 )
+    {
+      /*
+        autolevel all channels equally
+      */
+      GetImageChannelRange(image, channel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      return LevelImageChannel(image, channel, min, max, 1.0);
+    }
+
+  /*
+    autolevel each channel separateally
+  */
+  status = MagickTrue;
+  if ((channel & RedChannel) != 0)
+    {
+      GetImageChannelRange(image, RedChannel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      status = status && LevelImageChannel(image, RedChannel, min, max, 1.0);
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      GetImageChannelRange(image, GreenChannel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      status = status && LevelImageChannel(image, GreenChannel, min, max, 1.0);
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      GetImageChannelRange(image, BlueChannel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      status = status && LevelImageChannel(image, BlueChannel, min, max, 1.0);
+    }
+  if (((channel & OpacityChannel) != 0) &&
+      (image->matte == MagickTrue))
+    {
+      GetImageChannelRange(image, OpacityChannel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      status = status && LevelImageChannel(image, OpacityChannel, min, max, 1.0);
+    }
+  if (((channel & IndexChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    {
+      GetImageChannelRange(image, IndexChannel, &min, &max, &image->exception);
+      min += black_value;  max -= white_value;
+      status = status && LevelImageChannel(image, IndexChannel, min, max, 1.0);
+    }
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
diff --git a/magick/histogram.h b/magick/histogram.h
new file mode 100644
index 0000000..cbf6ff8
--- /dev/null
+++ b/magick/histogram.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2009 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 MagickBooleanType
+  MinMaxStretchImage(Image *,const ChannelType,const double,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/identify.c b/magick/identify.c
new file mode 100644
index 0000000..9feddef
--- /dev/null
+++ b/magick/identify.c
@@ -0,0 +1,1002 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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 "magick/studio.h"
+#include "magick/annotate.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/client.h"
+#include "magick/coder.h"
+#include "magick/color.h"
+#include "magick/configure.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/delegate.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/identify.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/module.h"
+#include "magick/monitor.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/prepress.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/registry.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/signature.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/timer.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
+#include <lcms/lcms.h>
+#else
+#include "lcms.h"
+#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.
+%
+*/
+
+MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
+  const MagickBooleanType verbose)
+{
+#define IdentifyFormat "    %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"
+
+  char
+    color[MaxTextExtent],
+    format[MaxTextExtent],
+    key[MaxTextExtent];
+
+  ColorspaceType
+    colorspace;
+
+  const char
+    *artifact,
+    *name,
+    *property,
+    *registry,
+    *value;
+
+  const MagickInfo
+    *magick_info;
+
+  const PixelPacket
+    *pixels;
+
+  double
+    elapsed_time,
+    user_time;
+
+  ExceptionInfo
+    *exception;
+
+  ImageType
+    type;
+
+  long
+    y;
+
+  MagickBooleanType
+    ping;
+
+  register long
+    i,
+    x;
+
+  unsigned long
+    scale;
+
+  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) fprintf(file,"%s=>",image->magick_filename);
+       if ((GetPreviousImageInList(image) == (Image *) NULL) &&
+           (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0))
+        (void) fprintf(file,"%s ",image->filename);
+      else
+        (void) fprintf(file,"%s[%lu] ",image->filename,image->scene);
+      (void) fprintf(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) fprintf(file,"%lux%lu=>",image->magick_columns,
+            image->magick_rows);
+      (void) fprintf(file,"%lux%lu ",image->columns,image->rows);
+      if ((image->page.width != 0) || (image->page.height != 0) ||
+          (image->page.x != 0) || (image->page.y != 0))
+        (void) fprintf(file,"%lux%lu%+ld%+ld ",image->page.width,
+          image->page.height,image->page.x,image->page.y);
+      (void) fprintf(file,"%lu-bit ",image->depth);
+      if (image->type != UndefinedType)
+        (void) fprintf(file,"%s ",MagickOptionToMnemonic(MagickTypeOptions,
+          (long) image->type));
+      if (image->storage_class == DirectClass)
+        {
+          (void) fprintf(file,"DirectClass ");
+          if (image->total_colors != 0)
+            {
+              (void) FormatMagickSize(image->total_colors,format);
+              (void) fprintf(file,"%s ",format);
+            }
+        }
+      else
+        if (image->total_colors <= image->colors)
+          (void) fprintf(file,"PseudoClass %luc ",image->colors);
+        else
+          (void) fprintf(file,"PseudoClass %lu=>%luc ",image->total_colors,
+            image->colors);
+      if (image->error.mean_error_per_pixel != 0.0)
+        (void) fprintf(file,"%ld/%f/%fdb ",(long)
+          (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),format);
+          (void) fprintf(file,"%s ",format);
+        }
+      if (elapsed_time > 0.06)
+        (void) fprintf(file,"%0.3fu %ld:%02ld",user_time,(long)
+          (elapsed_time/60.0+0.5),(long) ceil(fmod(elapsed_time,60.0)));
+      (void) fprintf(file,"\n");
+      (void) fflush(file);
+      return(ferror(file) != 0 ? MagickFalse : MagickTrue);
+    }
+  /*
+    Display verbose info about the image.
+  */
+  exception=AcquireExceptionInfo();
+  pixels=GetVirtualPixels(image,0,0,1,1,exception);
+  exception=DestroyExceptionInfo(exception);
+  ping=pixels == (const PixelPacket *) NULL ? MagickTrue : MagickFalse;
+  type=GetImageType(image,&image->exception);
+  (void) SignatureImage(image);
+  (void) fprintf(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) fprintf(file,"  Base filename: %s\n",filename);
+      }
+  magick_info=GetMagickInfo(image->magick,&image->exception);
+  if ((magick_info == (const MagickInfo *) NULL) ||
+      (*GetMagickDescription(magick_info) == '\0'))
+    (void) fprintf(file,"  Format: %s\n",image->magick);
+  else
+    (void) fprintf(file,"  Format: %s (%s)\n",image->magick,
+      GetMagickDescription(magick_info));
+  (void) fprintf(file,"  Class: %s\n",MagickOptionToMnemonic(MagickClassOptions,
+    (long) image->storage_class));
+  (void) fprintf(file,"  Geometry: %lux%lu%+ld%+ld\n",image->columns,
+    image->rows,image->tile_offset.x,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) fprintf(file,"  Base geometry: %lux%lu\n",image->magick_columns,
+        image->magick_rows);
+  if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
+    {
+      (void) fprintf(file,"  Resolution: %gx%g\n",image->x_resolution,
+        image->y_resolution);
+      (void) fprintf(file,"  Print size: %gx%g\n",(double) image->columns/
+        image->x_resolution,(double) image->rows/image->y_resolution);
+    }
+  (void) fprintf(file,"  Units: %s\n",MagickOptionToMnemonic(
+    MagickResolutionOptions,(long) image->units));
+  (void) fprintf(file,"  Type: %s\n",MagickOptionToMnemonic(MagickTypeOptions,
+    (long) type));
+  if (image->type != UndefinedType)
+    (void) fprintf(file,"  Base type: %s\n",MagickOptionToMnemonic(
+      MagickTypeOptions,(long) image->type));
+  (void) fprintf(file,"  Endianess: %s\n",MagickOptionToMnemonic(
+    MagickEndianOptions,(long) image->endian));
+  /*
+    Detail channel depth and extrema.
+  */
+  (void) fprintf(file,"  Colorspace: %s\n",MagickOptionToMnemonic(
+    MagickColorspaceOptions,(long) image->colorspace));
+  if (ping == MagickFalse)
+    {
+      ChannelStatistics
+        *channel_statistics;
+
+      unsigned long
+        depth;
+
+      depth=GetImageDepth(image,&image->exception);
+      if (image->depth == depth)
+        (void) fprintf(file,"  Depth: %lu-bit\n",image->depth);
+      else
+        (void) fprintf(file,"  Depth: %lu/%lu-bit\n",image->depth,depth);
+      channel_statistics=GetImageChannelStatistics(image,&image->exception);
+      (void) fprintf(file,"  Channel depth:\n");
+      colorspace=image->colorspace;
+      if (IsGrayImage(image,&image->exception) != MagickFalse)
+        colorspace=GRAYColorspace;
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) fprintf(file,"    red: %lu-bit\n",
+            channel_statistics[RedChannel].depth);
+          (void) fprintf(file,"    green: %lu-bit\n",
+            channel_statistics[GreenChannel].depth);
+          (void) fprintf(file,"    blue: %lu-bit\n",
+            channel_statistics[BlueChannel].depth);
+          if (image->matte != MagickFalse)
+            (void) fprintf(file,"    alpha: %lu-bit\n",
+              channel_statistics[OpacityChannel].depth);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) fprintf(file,"    cyan: %lu-bit\n",
+            channel_statistics[CyanChannel].depth);
+          (void) fprintf(file,"    magenta: %lu-bit\n",
+            channel_statistics[MagentaChannel].depth);
+          (void) fprintf(file,"    yellow: %lu-bit\n",
+            channel_statistics[YellowChannel].depth);
+          (void) fprintf(file,"    black: %lu-bit\n",
+            channel_statistics[BlackChannel].depth);
+          if (image->matte != MagickFalse)
+            (void) fprintf(file,"    alpha: %lu-bit\n",
+              channel_statistics[OpacityChannel].depth);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) fprintf(file,"    gray: %lu-bit\n",
+            channel_statistics[GrayChannel].depth);
+          if (image->matte != MagickFalse)
+            (void) fprintf(file,"    alpha: %lu-bit\n",
+              channel_statistics[OpacityChannel].depth);
+          break;
+        }
+      }
+      scale=1;
+      if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
+        scale=QuantumRange/((unsigned long) QuantumRange >> ((unsigned long)
+          MAGICKCORE_QUANTUM_DEPTH-image->depth));
+      (void) fprintf(file,"  Channel statistics:\n");
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) fprintf(file,IdentifyFormat,"red",(Quantum)
+            (channel_statistics[RedChannel].minima/scale),(double)
+            channel_statistics[RedChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[RedChannel].maxima/scale),(double)
+            channel_statistics[RedChannel].maxima/(double) QuantumRange,
+            channel_statistics[RedChannel].mean/(double) scale,
+            channel_statistics[RedChannel].mean/(double) QuantumRange,
+            channel_statistics[RedChannel].standard_deviation/(double) scale,
+            channel_statistics[RedChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[RedChannel].kurtosis,
+            channel_statistics[RedChannel].skewness);
+          (void) fprintf(file,IdentifyFormat,"green",(Quantum)
+            (channel_statistics[GreenChannel].minima/scale),(double)
+            channel_statistics[GreenChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[GreenChannel].maxima/scale),(double)
+            channel_statistics[GreenChannel].maxima/(double) QuantumRange,
+            channel_statistics[GreenChannel].mean/(double) scale,
+            channel_statistics[GreenChannel].mean/(double) QuantumRange,
+            channel_statistics[GreenChannel].standard_deviation/(double) scale,
+            channel_statistics[GreenChannel].standard_deviation/(double)
+            QuantumRange,
+            channel_statistics[GreenChannel].kurtosis,
+            channel_statistics[GreenChannel].skewness);
+          (void) fprintf(file,IdentifyFormat,"blue",(Quantum)
+            (channel_statistics[BlueChannel].minima/scale),(double)
+            channel_statistics[BlueChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[BlueChannel].maxima/scale),(double)
+            channel_statistics[BlueChannel].maxima/(double) QuantumRange,
+            channel_statistics[BlueChannel].mean/(double) scale,
+            channel_statistics[BlueChannel].mean/(double) QuantumRange,
+            channel_statistics[BlueChannel].standard_deviation/(double) scale,
+            channel_statistics[BlueChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[BlueChannel].kurtosis,
+            channel_statistics[BlueChannel].skewness);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) fprintf(file,IdentifyFormat,"cyan",(Quantum)
+            (channel_statistics[CyanChannel].minima/scale),(double)
+            channel_statistics[CyanChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[CyanChannel].maxima/scale),(double)
+            channel_statistics[CyanChannel].maxima/(double) QuantumRange,
+            channel_statistics[CyanChannel].mean/(double) scale,
+            channel_statistics[CyanChannel].mean/(double) QuantumRange,
+            channel_statistics[CyanChannel].standard_deviation/(double) scale,
+            channel_statistics[CyanChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[CyanChannel].kurtosis,
+            channel_statistics[CyanChannel].skewness);
+          (void) fprintf(file,IdentifyFormat,"magenta",(Quantum)
+            (channel_statistics[MagentaChannel].minima/scale),(double)
+            channel_statistics[MagentaChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[MagentaChannel].maxima/scale),(double)
+            channel_statistics[MagentaChannel].maxima/(double) QuantumRange,
+            channel_statistics[MagentaChannel].mean/(double) scale,
+            channel_statistics[MagentaChannel].mean/(double) QuantumRange,
+            channel_statistics[MagentaChannel].standard_deviation/(double)
+            scale,channel_statistics[MagentaChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[MagentaChannel].kurtosis,
+            channel_statistics[MagentaChannel].skewness);
+          (void) fprintf(file,IdentifyFormat,"yellow",(Quantum)
+            (channel_statistics[YellowChannel].minima/scale),(double)
+            channel_statistics[YellowChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[YellowChannel].maxima/scale),(double)
+            channel_statistics[YellowChannel].maxima/(double) QuantumRange,
+            channel_statistics[YellowChannel].mean/(double) scale,
+            channel_statistics[YellowChannel].mean/(double) QuantumRange,
+            channel_statistics[YellowChannel].standard_deviation/(double) scale,
+            channel_statistics[YellowChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[YellowChannel].kurtosis,
+            channel_statistics[YellowChannel].skewness);
+          (void) fprintf(file,IdentifyFormat,"black",(Quantum)
+            (channel_statistics[BlackChannel].minima/scale),(double)
+            channel_statistics[BlackChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[BlackChannel].maxima/scale),(double)
+            channel_statistics[BlackChannel].maxima/(double) QuantumRange,
+            channel_statistics[BlackChannel].mean/(double) scale,
+            channel_statistics[BlackChannel].mean/(double) QuantumRange,
+            channel_statistics[BlackChannel].standard_deviation/(double) scale,
+            channel_statistics[BlackChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[BlackChannel].kurtosis,
+            channel_statistics[BlackChannel].skewness);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) fprintf(file,IdentifyFormat,"gray",(Quantum)
+            (channel_statistics[GrayChannel].minima/scale),(double)
+            channel_statistics[GrayChannel].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[GrayChannel].maxima/scale),(double)
+            channel_statistics[GrayChannel].maxima/(double) QuantumRange,
+            channel_statistics[GrayChannel].mean/(double) scale,
+            channel_statistics[GrayChannel].mean/(double) QuantumRange,
+            channel_statistics[GrayChannel].standard_deviation/(double) scale,
+            channel_statistics[GrayChannel].standard_deviation/(double)
+            QuantumRange,channel_statistics[GrayChannel].kurtosis,
+            channel_statistics[GrayChannel].skewness);
+          break;
+        }
+      }
+      if (image->matte != MagickFalse)
+        (void) fprintf(file,IdentifyFormat,"alpha",(Quantum)
+          ((QuantumRange-channel_statistics[AlphaChannel].maxima)/scale),
+          (double) (QuantumRange-channel_statistics[AlphaChannel].maxima)/
+          (double) QuantumRange, (Quantum) ((QuantumRange-
+          channel_statistics[AlphaChannel].minima)/scale),(double)
+          (QuantumRange-channel_statistics[AlphaChannel].minima)/(double)
+          QuantumRange,(QuantumRange-channel_statistics[AlphaChannel].mean)/
+          (double) scale,(QuantumRange-channel_statistics[AlphaChannel].mean)/
+          (double) QuantumRange,
+          channel_statistics[AlphaChannel].standard_deviation/(double) scale,
+          channel_statistics[AlphaChannel].standard_deviation/(double)
+          QuantumRange,channel_statistics[AlphaChannel].kurtosis,
+          channel_statistics[AlphaChannel].skewness);
+      if (colorspace != GRAYColorspace)
+        {
+          (void) fprintf(file,"  Image statistics:\n");
+          (void) fprintf(file,IdentifyFormat,"Overall",(Quantum)
+            (channel_statistics[AllChannels].minima/scale),(double)
+            channel_statistics[AllChannels].minima/(double) QuantumRange,
+            (Quantum) (channel_statistics[AllChannels].maxima/scale),(double)
+            channel_statistics[AllChannels].maxima/(double) QuantumRange,
+            channel_statistics[AllChannels].mean/(double) scale,
+            channel_statistics[AllChannels].mean/(double) QuantumRange,
+            channel_statistics[AllChannels].standard_deviation/(double) scale,
+            channel_statistics[AllChannels].standard_deviation/(double)
+            QuantumRange,channel_statistics[AllChannels].kurtosis,
+            channel_statistics[AllChannels].skewness);
+        }
+      channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+        channel_statistics);
+      if (image->colorspace == CMYKColorspace)
+        (void) fprintf(file,"  Total ink density: %.0f%%\n",100.0*
+          GetImageTotalInkDensity(image)/(double) QuantumRange);
+      x=0;
+      if (image->matte != MagickFalse)
+        {
+          register const IndexPacket
+            *indexes;
+
+          register const PixelPacket
+            *p;
+
+          p=(PixelPacket *) NULL;
+          indexes=(IndexPacket *) NULL;
+          for (y=0; y < (long) image->rows; y++)
+          {
+            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(image);
+            for (x=0; x < (long) image->columns; x++)
+            {
+              if (p->opacity == (Quantum) TransparentOpacity)
+                break;
+              p++;
+            }
+            if (x < (long) image->columns)
+              break;
+          }
+          if ((x < (long) image->columns) || (y < (long) image->rows))
+            {
+              char
+                tuple[MaxTextExtent];
+
+              MagickPixelPacket
+                pixel;
+
+              GetMagickPixelPacket(image,&pixel);
+              SetMagickPixelPacket(image,p,indexes+x,&pixel);
+              (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
+                &image->exception);
+              (void) fprintf(file,"  Alpha: %s ",tuple);
+              GetColorTuple(&pixel,MagickTrue,tuple);
+              (void) fprintf(file,"  %s\n",tuple);
+            }
+        }
+      if (ping == MagickFalse)
+        {
+          artifact=GetImageArtifact(image,"identify:unique");
+          if ((artifact != (const char *) NULL) &&
+              (IsMagickTrue(artifact) != MagickFalse))
+            (void) fprintf(file,"  Colors: %lu\n",GetNumberColors(image,
+              (FILE *) NULL,&image->exception));
+          if (IsHistogramImage(image,&image->exception) != MagickFalse)
+            {
+              (void) fprintf(file,"  Histogram:\n");
+              (void) GetNumberColors(image,file,&image->exception);
+            }
+        }
+    }
+  if (image->storage_class == PseudoClass)
+    {
+      (void) fprintf(file,"  Colormap: %lu\n",image->colors);
+      if (image->colors <= 1024)
+        {
+          char
+            color[MaxTextExtent],
+            hex[MaxTextExtent],
+            tuple[MaxTextExtent];
+
+          MagickPixelPacket
+            pixel;
+
+          register PixelPacket
+            *__restrict p;
+
+          GetMagickPixelPacket(image,&pixel);
+          p=image->colormap;
+          for (i=0; i < (long) image->colors; i++)
+          {
+            SetMagickPixelPacket(image,p,(IndexPacket *) NULL,&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,IndexChannel,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,
+              &image->exception);
+            GetColorTuple(&pixel,MagickTrue,hex);
+            (void) fprintf(file,"  %8ld: %s %s %s\n",i,tuple,hex,color);
+            p++;
+          }
+        }
+    }
+  if (image->error.mean_error_per_pixel != 0.0)
+    (void) fprintf(file,"  Mean error per pixel: %g\n",
+      image->error.mean_error_per_pixel);
+  if (image->error.normalized_mean_error != 0.0)
+    (void) fprintf(file,"  Normalized mean error: %g\n",
+      image->error.normalized_mean_error);
+  if (image->error.normalized_maximum_error != 0.0)
+    (void) fprintf(file,"  Normalized maximum error: %g\n",
+      image->error.normalized_maximum_error);
+  (void) fprintf(file,"  Rendering intent: %s\n",MagickOptionToMnemonic(
+    MagickIntentOptions,(long) image->rendering_intent));
+  if (image->gamma != 0.0)
+    (void) fprintf(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) fprintf(file,"  Chromaticity:\n");
+      (void) fprintf(file,"    red primary: (%g,%g)\n",
+        image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
+      (void) fprintf(file,"    green primary: (%g,%g)\n",
+        image->chromaticity.green_primary.x,
+        image->chromaticity.green_primary.y);
+      (void) fprintf(file,"    blue primary: (%g,%g)\n",
+        image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
+      (void) fprintf(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) fprintf(file,"  Tile geometry: %lux%lu%+ld%+ld\n",
+      image->extract_info.width,image->extract_info.height,
+      image->extract_info.x,image->extract_info.y);
+  (void) fprintf(file,"  Interlace: %s\n",MagickOptionToMnemonic(
+    MagickInterlaceOptions,(long) image->interlace));
+  (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
+    &image->exception);
+  (void) fprintf(file,"  Background color: %s\n",color);
+  (void) QueryColorname(image,&image->border_color,SVGCompliance,color,
+    &image->exception);
+  (void) fprintf(file,"  Border color: %s\n",color);
+  (void) QueryColorname(image,&image->matte_color,SVGCompliance,color,
+    &image->exception);
+  (void) fprintf(file,"  Matte color: %s\n",color);
+  (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
+    &image->exception);
+  (void) fprintf(file,"  Transparent color: %s\n",color);
+  if ((image->page.width != 0) || (image->page.height != 0) ||
+      (image->page.x != 0) || (image->page.y != 0))
+    (void) fprintf(file,"  Page geometry: %lux%lu%+ld%+ld\n",image->page.width,
+      image->page.height,image->page.x,image->page.y);
+  if ((image->page.x != 0) || (image->page.y != 0))
+    (void) fprintf(file,"  Origin geometry: %+ld%+ld\n",image->page.x,
+      image->page.y);
+  (void) fprintf(file,"  Dispose: %s\n",MagickOptionToMnemonic(
+    MagickDisposeOptions,(long) image->dispose));
+  if (image->delay != 0)
+    (void) fprintf(file,"  Delay: %lux%ld\n",image->delay,
+      image->ticks_per_second);
+  if (image->iterations != 1)
+    (void) fprintf(file,"  Iterations: %lu\n",image->iterations);
+  if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
+    (void) fprintf(file,"  Scene: %lu of %lu\n",image->scene,
+      GetImageListLength(image));
+  else
+    if (image->scene != 0)
+      (void) fprintf(file,"  Scene: %lu\n",image->scene);
+  (void) fprintf(file,"  Compression: %s\n",MagickOptionToMnemonic(
+    MagickCompressOptions,(long) image->compression));
+  if (image->quality != UndefinedCompressionQuality)
+    (void) fprintf(file,"  Quality: %lu\n",image->quality);
+  (void) fprintf(file,"  Orientation: %s\n",MagickOptionToMnemonic(
+    MagickOrientationOptions,(long) image->orientation));
+  if (image->montage != (char *) NULL)
+    (void) fprintf(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) fprintf(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) fprintf(file,"    %s",image_info->filename);
+        handler=SetWarningHandler((WarningHandler) NULL);
+        tile=ReadImage(image_info,&image->exception);
+        (void) SetWarningHandler(handler);
+        if (tile == (Image *) NULL)
+          {
+            (void) fprintf(file,"\n");
+            continue;
+          }
+        (void) fprintf(file," %lux%lu %s\n",tile->magick_columns,
+          tile->magick_rows,tile->magick);
+        (void) SignatureImage(tile);
+        ResetImagePropertyIterator(tile);
+        property=GetNextImageProperty(tile);
+        while (property != (const char *) NULL)
+        {
+          (void) fprintf(file,"  %s:\n",property);
+          value=GetImageProperty(tile,property);
+          if (value != (const char *) NULL)
+            (void) fprintf(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) fprintf(file,"  Properties:\n");
+      while (property != (const char *) NULL)
+      {
+        (void) fprintf(file,"    %c",*property);
+        if (strlen(property) > 1)
+          (void) fprintf(file,"%s: ",property+1);
+        if (strlen(property) > 80)
+          (void) fputc('\n',file);
+        value=GetImageProperty(image,property);
+        if (value != (const char *) NULL)
+          (void) fprintf(file,"%s\n",value);
+        property=GetNextImageProperty(image);
+      }
+    }
+  (void) FormatMagickString(key,MaxTextExtent,"8BIM:1999,2998:#1");
+  value=GetImageProperty(image,key);
+  if (value != (const char *) NULL)
+    {
+      /*
+        Display clipping path.
+      */
+      (void) fprintf(file,"  Clipping path: ");
+      if (strlen(value) > 80)
+        (void) fputc('\n',file);
+      (void) fprintf(file,"%s\n",value);
+    }
+  ResetImageProfileIterator(image);
+  name=GetNextImageProfile(image);
+  if (name != (char *) NULL)
+    {
+      const StringInfo
+        *profile;
+
+      /*
+        Identify image profiles.
+      */
+      (void) fprintf(file,"  Profiles:\n");
+      while (name != (char *) NULL)
+      {
+        profile=GetImageProfile(image,name);
+        if (profile == (StringInfo *) NULL)
+          continue;
+        (void) fprintf(file,"    Profile-%s: %lu bytes\n",name,(unsigned long)
+          GetStringInfoLength(profile));
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+        if ((LocaleCompare(name,"icc") == 0) ||
+            (LocaleCompare(name,"icm") == 0))
+          {
+            cmsHPROFILE
+              icc_profile;
+
+            icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
+              (DWORD) GetStringInfoLength(profile));
+            if (icc_profile != (cmsHPROFILE *) NULL)
+              {
+                const char
+                  *name;
+
+                name=cmsTakeProductName(icc_profile);
+                if (name != (const char *) NULL)
+                  (void) fprintf(file,"      %s\n",name);
+                (void) cmsCloseProfile(icc_profile);
+              }
+          }
+#endif
+        if (LocaleCompare(name,"iptc") == 0)
+          {
+            char
+              *attribute,
+              **attribute_list;
+
+            const char
+              *tag;
+
+            long
+              dataset,
+              record,
+              sentinel;
+
+            register long
+              j;
+
+            size_t
+              length,
+              profile_length;
+
+            profile_length=GetStringInfoLength(profile);
+            for (i=0; i < (long) profile_length; i+=(long) 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) fprintf(file,"      %s[%ld,%ld]: ",tag,dataset,record);
+              length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
+              length|=GetStringInfoDatum(profile)[i++];
+              attribute=(char *) NULL;
+              if (~length >= MaxTextExtent)
+                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) fprintf(file,"  Artifacts:\n");
+      while (artifact != (const char *) NULL)
+      {
+        (void) fprintf(file,"    %c",*artifact);
+        if (strlen(artifact) > 1)
+          (void) fprintf(file,"%s: ",artifact+1);
+        if (strlen(artifact) > 80)
+          (void) fputc('\n',file);
+        value=GetImageArtifact(image,artifact);
+        if (value != (const char *) NULL)
+          (void) fprintf(file,"%s\n",value);
+        artifact=GetNextImageArtifact(image);
+      }
+    }
+  ResetImageRegistryIterator();
+  registry=GetNextImageRegistry();
+  if (registry != (const char *) NULL)
+    {
+      /*
+        Display image registry.
+      */
+      (void) fprintf(file,"  Registry:\n");
+      while (registry != (const char *) NULL)
+      {
+        (void) fprintf(file,"    %c",*registry);
+        if (strlen(registry) > 1)
+          (void) fprintf(file,"%s: ",registry+1);
+        if (strlen(registry) > 80)
+          (void) fputc('\n',file);
+        value=(const char *) GetImageRegistry(StringRegistryType,registry,
+          &image->exception);
+        if (value != (const char *) NULL)
+          (void) fprintf(file,"%s\n",value);
+        registry=GetNextImageRegistry();
+      }
+    }
+  (void) fprintf(file,"  Tainted: %s\n",MagickOptionToMnemonic(
+    MagickBooleanOptions,(long) image->taint));
+  (void) FormatMagickSize(GetBlobSize(image),format);
+  (void) fprintf(file,"  Filesize: %s\n",format);
+  (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,format);
+  (void) fprintf(file,"  Number pixels: %s\n",format);
+  if (elapsed_time > 0.06)
+    {
+      (void) FormatMagickSize((MagickSizeType) ((double) image->columns*
+        image->rows/elapsed_time+0.5),format);
+      (void) fprintf(file,"  Pixels per second: %s\n",format);
+      (void) fprintf(file,"  User time: %0.3fu\n",user_time);
+      (void) fprintf(file,"  Elapsed time: %ld:%02ld\n",(long) (elapsed_time/
+        60.0+0.5),(long) ceil(fmod(elapsed_time,60.0)));
+    }
+  (void) fprintf(file,"  Version: %s\n",GetMagickVersion(
+    (unsigned long *) NULL));
+  (void) fflush(file);
+  return(ferror(file) != 0 ? MagickFalse : MagickTrue);
+}
diff --git a/magick/identify.h b/magick/identify.h
new file mode 100644
index 0000000..a6b4b4e
--- /dev/null
+++ b/magick/identify.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2009 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/magick/image-private.h b/magick/image-private.h
new file mode 100644
index 0000000..0c0a8e0
--- /dev/null
+++ b/magick/image-private.h
@@ -0,0 +1,86 @@
+/*
+  Copyright 1999-2009 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 MagickPI  3.14159265358979323846264338327950288419716939937510
+#define Magick2PI  6.28318530717958647692528676655900576839433879875020
+#define MagickPI2  1.57079632679489661923132169163975144209858469968755
+#define MagickSQ1_2  0.7071067811865475244008443621048490
+#define MagickSQ2PI  2.50662827463100024161235523934010416269302368164062
+#define QuantumScale  ((double) 1.0/(double) QuantumRange)
+#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(MagickPI*degrees/180.0);
+}
+
+static inline MagickRealType RadiansToDegrees(const MagickRealType radians)
+{
+  return(180.0*radians/MagickPI);
+}
+
+static inline unsigned char ScaleColor5to8(const unsigned long color)
+{
+  return((unsigned char) (((color) << 3) | ((color) >> 2)));
+}
+
+static inline unsigned char ScaleColor6to8(const unsigned long color)
+{
+  return((unsigned char) (((color) << 2) | ((color) >> 4)));
+}
+
+static inline unsigned long ScaleColor8to5(const unsigned char color)
+{
+  return((unsigned long) (((color) & ~0x07) >> 3));
+}
+
+static inline unsigned long ScaleColor8to6(const unsigned char color)
+{
+  return((unsigned long) (((color) & ~0x03) >> 2));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/image.c b/magick/image.c
new file mode 100644
index 0000000..9fa0eda
--- /dev/null
+++ b/magick/image.c
@@ -0,0 +1,4475 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                     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-2009 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 "magick/studio.h"
+#include "magick/animate.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/compress.h"
+#include "magick/constitute.h"
+#include "magick/deprecate.h"
+#include "magick/display.h"
+#include "magick/draw.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/image-private.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/module.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/paint.h"
+#include "magick/pixel-private.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantize.h"
+#include "magick/random_.h"
+#include "magick/segment.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/threshold.h"
+#include "magick/timer.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#include "magick/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)
+{
+  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->cache=AcquirePixelCache(0);
+  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->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);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long colors)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colors: the number of colors in the image colormap.
+%
+*/
+
+static inline unsigned long MagickMax(const unsigned long x,
+  const unsigned long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline unsigned long MagickMin(const unsigned long x,
+  const unsigned long y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType AcquireImageColormap(Image *image,
+  const unsigned long colors)
+{
+  register long
+    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=MagickMin(colors,MaxColormapSize);
+  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 < (long) image->colors; i++)
+  {
+    unsigned long
+      pixel;
+
+    pixel=(unsigned long) (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].opacity=OpaqueOpacity;
+  }
+  return(SetImageStorageClass(image,PseudoClass));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 *image,const MagickBooleanType stack,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: 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 *image,
+  const MagickBooleanType stack,ExceptionInfo *exception)
+{
+#define AppendImageTag  "Append/Image"
+
+  CacheView
+    *append_view,
+    *image_view;
+
+  Image
+    *append_image;
+
+  long
+    n,
+    x_offset,
+    y,
+    y_offset;
+
+  MagickBooleanType
+    matte,
+    proceed,
+    status;
+
+  RectangleInfo
+    geometry;
+
+  register const Image
+    *next;
+
+  unsigned long
+    height,
+    number_images,
+    width;
+
+  /*
+    Ensure the image have the same column 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);
+  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;
+  }
+  /*
+    Initialize append next attributes.
+  */
+  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 < (long) 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)
+#endif
+    for (y=0; y < (long) image->rows; y++)
+    {
+      MagickBooleanType
+        sync;
+
+      register const IndexPacket
+        *__restrict indexes;
+
+      register const PixelPacket
+        *__restrict p;
+
+      register IndexPacket
+        *__restrict append_indexes;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+        {
+          status=MagickFalse;
+          continue;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      append_indexes=GetCacheViewAuthenticIndexQueue(append_view);
+      for (x=0; x < (long) image->columns; x++)
+      {
+        q->red=p->red;
+        q->green=p->green;
+        q->blue=p->blue;
+        q->opacity=OpaqueOpacity;
+        if (image->matte != MagickFalse)
+          q->opacity=p->opacity;
+        if (image->colorspace == CMYKColorspace)
+          append_indexes[x]=indexes[x];
+        p++;
+        q++;
+      }
+      sync=SyncCacheViewAuthenticPixels(append_view,exception);
+      if (sync == MagickFalse)
+        continue;
+    }
+    image_view=DestroyCacheView(image_view);
+    proceed=SetImageProgress(image,AppendImageTag,n,number_images);
+    if (proceed == MagickFalse)
+      break;
+    if (stack == MagickFalse)
+      {
+        x_offset+=image->columns;
+        y_offset=0;
+      }
+    else
+      {
+        x_offset=0;
+        y_offset+=image->rows;
+      }
+    image=GetNextImageInList(image);
+  }
+  append_view=DestroyCacheView(append_view);
+  if (status == MagickFalse)
+    append_image=DestroyImage(append_image);
+  return(append_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A v e r a g e I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AverageImages() takes a set of images and averages them together.  Each
+%  image in the set must have the same width and height.  AverageImages()
+%  returns a single image with each corresponding pixel component of each
+%  image averaged.   On failure, a NULL image is returned and exception
+%  describes the reason for the failure.
+%
+%  The format of the AverageImages method is:
+%
+%      Image *AverageImages(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.
+%
+*/
+
+static MagickPixelPacket **DestroyPixelThreadSet(MagickPixelPacket **pixels)
+{
+  register long
+    i;
+
+  assert(pixels != (MagickPixelPacket **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (MagickPixelPacket *) NULL)
+      pixels[i]=(MagickPixelPacket *) RelinquishMagickMemory(pixels[i]);
+  pixels=(MagickPixelPacket **) RelinquishAlignedMemory(pixels);
+  return(pixels);
+}
+
+static MagickPixelPacket **AcquirePixelThreadSet(const Image *image)
+{
+  register long
+    i,
+    j;
+
+  MagickPixelPacket
+    **pixels;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(MagickPixelPacket **) AcquireAlignedMemory(number_threads,
+    sizeof(*pixels));
+  if (pixels == (MagickPixelPacket **) NULL)
+    return((MagickPixelPacket **) NULL);
+  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+  for (i=0; i < (long) number_threads; i++)
+  {
+    pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(image->columns,
+      sizeof(**pixels));
+    if (pixels[i] == (MagickPixelPacket *) NULL)
+      return(DestroyPixelThreadSet(pixels));
+    for (j=0; j < (long) image->columns; j++)
+      GetMagickPixelPacket(image,&pixels[i][j]);
+  }
+  return(pixels);
+}
+
+MagickExport Image *AverageImages(const Image *image,ExceptionInfo *exception)
+{
+#define AverageImageTag  "Average/Image"
+
+  CacheView
+    *average_view;
+
+  const Image
+    *next;
+
+  Image
+    *average_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    **average_pixels,
+    zero;
+
+  unsigned long
+    number_images;
+
+  /*
+    Ensure the image are the same size.
+  */
+  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->columns != image->columns) || (next->rows != image->rows))
+      ThrowImageException(OptionError,"ImageWidthsOrHeightsDiffer");
+  /*
+    Initialize average next attributes.
+  */
+  average_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (average_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(average_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&average_image->exception);
+      average_image=DestroyImage(average_image);
+      return((Image *) NULL);
+    }
+  average_pixels=AcquirePixelThreadSet(image);
+  if (average_pixels == (MagickPixelPacket **) NULL)
+    {
+      average_image=DestroyImage(average_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Average image pixels.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetMagickPixelPacket(image,&zero);
+  number_images=GetImageListLength(image);
+  average_view=AcquireCacheView(average_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+  for (y=0; y < (long) average_image->rows; y++)
+  {
+    CacheView
+      *image_view;
+
+    const Image
+      *next;
+
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict average_indexes;
+
+    register long
+      i,
+      x;
+
+    register MagickPixelPacket
+      *average_pixel;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(average_view,0,y,average_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    average_indexes=GetCacheViewAuthenticIndexQueue(average_view);
+    pixel=zero;
+    average_pixel=average_pixels[GetOpenMPThreadId()];
+    for (x=0; x < (long) average_image->columns; x++)
+      average_pixel[x]=zero;
+    next=image;
+    for (i=0; i < (long) number_images; i++)
+    {
+      register const IndexPacket
+        *indexes;
+
+      register const PixelPacket
+        *p;
+
+      image_view=AcquireCacheView(next);
+      p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          image_view=DestroyCacheView(image_view);
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+      for (x=0; x < (long) next->columns; x++)
+      {
+        SetMagickPixelPacket(next,p,indexes+x,&pixel);
+        average_pixel[x].red+=QuantumScale*pixel.red;
+        average_pixel[x].green+=QuantumScale*pixel.green;
+        average_pixel[x].blue+=QuantumScale*pixel.blue;
+        average_pixel[x].opacity+=QuantumScale*pixel.opacity;
+        if (average_image->colorspace == CMYKColorspace)
+          average_pixel[x].index+=QuantumScale*pixel.index;
+        p++;
+      }
+      image_view=DestroyCacheView(image_view);
+      next=GetNextImageInList(next);
+    }
+    for (x=0; x < (long) average_image->columns; x++)
+    {
+      average_pixel[x].red=(MagickRealType) (QuantumRange*
+        average_pixel[x].red/number_images);
+      average_pixel[x].green=(MagickRealType) (QuantumRange*
+        average_pixel[x].green/number_images);
+      average_pixel[x].blue=(MagickRealType) (QuantumRange*
+        average_pixel[x].blue/number_images);
+      average_pixel[x].opacity=(MagickRealType) (QuantumRange*
+        average_pixel[x].opacity/number_images);
+      if (average_image->colorspace == CMYKColorspace)
+        average_pixel[x].index=(MagickRealType) (QuantumRange*
+          average_pixel[x].index/number_images);
+      SetPixelPacket(average_image,&average_pixel[x],q,average_indexes+x);
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(average_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_AverageImages)
+#endif
+        proceed=SetImageProgress(image,AverageImageTag,progress++,
+          average_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  average_view=DestroyCacheView(average_view);
+  average_pixels=DestroyPixelThreadSet(average_pixels);
+  if (status == MagickFalse)
+    average_image=DestroyImage(average_image);
+  return(average_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) FormatMagickString(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) FormatMagickString(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 unsigned long columns,
+%        const unsigned long 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 unsigned long columns,
+  const unsigned long 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->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;
+  (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=NewImageList();
+  clone_image->previous=NewImageList();
+  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->blob=CloneBlobInfo((BlobInfo *) NULL);
+  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);
+    }
+  scale=(MagickRealType) columns/(MagickRealType) image->columns;
+  clone_image->page.width=(unsigned long) (scale*image->page.width+0.5);
+  clone_image->page.x=(long) (scale*image->page.x+0.5);
+  clone_image->tile_offset.x=(long) (scale*image->tile_offset.x+0.5);
+  scale=(MagickRealType) rows/(MagickRealType) image->rows;
+  clone_image->page.height=(unsigned long) (scale*image->page.height+0.5);
+  clone_image->page.y=(long) (image->page.y*scale+0.5);
+  clone_image->tile_offset.y=(long) (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->pen=image_info->pen;
+  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->subimage=image_info->scene;  /* deprecated */
+  clone_info->subrange=image_info->number_scenes;  /* deprecated */
+  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;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  /*
+    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 & OpacityChannel) != 0)
+    combine_image->matte=MagickTrue;
+  (void) SetImageBackgroundColor(combine_image);
+  /*
+    Combine images.
+  */
+  status=MagickTrue;
+  progress=0;
+  combine_view=AcquireCacheView(combine_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) combine_image->rows; y++)
+  {
+    CacheView
+      *image_view;
+
+    const Image
+      *next;
+
+    PixelPacket
+      *pixels;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
+      1,exception);
+    if (pixels == (PixelPacket *) 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 PixelPacket *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (long) combine_image->columns; x++)
+        {
+          q->red=PixelIntensityToQuantum(p);
+          p++;
+          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 PixelPacket *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (long) combine_image->columns; x++)
+        {
+          q->green=PixelIntensityToQuantum(p);
+          p++;
+          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 PixelPacket *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (long) combine_image->columns; x++)
+        {
+          q->blue=PixelIntensityToQuantum(p);
+          p++;
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (long) combine_image->columns; x++)
+        {
+          q->opacity=PixelIntensityToQuantum(p);
+          p++;
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & IndexChannel) != 0) &&
+        (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
+      {
+        IndexPacket
+          *indexes;
+
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          continue;
+        indexes=GetCacheViewAuthenticIndexQueue(combine_view);
+        for (x=0; x < (long) combine_image->columns; x++)
+        {
+          indexes[x]=PixelIntensityToQuantum(p);
+          p++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_CombineImages)
+#endif
+        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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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 long displace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o displace:  displace the colormap this amount.
+%
+*/
+MagickExport MagickBooleanType CycleColormapImage(Image *image,
+  const long displace)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  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 < (long) image->rows; y++)
+  {
+    long
+      index;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=(long) (indexes[x]+displace) % image->colors;
+      if (index < 0)
+        index+=image->colors;
+      indexes[x]=(IndexPacket) index;
+      q->red=image->colormap[index].red;
+      q->green=image->colormap[index].green;
+      q->blue=image->colormap[index].blue;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+  (void) LockSemaphoreInfo(image->semaphore);
+  image->reference_count--;
+  if (image->reference_count == 0)
+    destroy=MagickTrue;
+  (void) UnlockSemaphoreInfo(image->semaphore);
+  if (destroy == MagickFalse)
+    return((Image *) NULL);
+  /*
+    Destroy image.
+  */
+  DestroyImagePixels(image);
+  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);
+#if !defined(MAGICKCORE_EXCLUDE_DEPRECATED)
+  DestroyImageAttributes(image);
+#endif
+  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)
+{
+  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;
+  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 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:
+%
+%      long GetImageReferenceCount(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport long GetImageReferenceCount(Image *image)
+{
+  long
+    reference_count;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  AcquireSemaphoreInfo(&image->semaphore);
+  reference_count=image->reference_count;
+  RelinquishSemaphoreInfo(image->semaphore);
+  return(reference_count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 (IsMonochromeImage(image,exception) != MagickFalse)
+    return(BilevelType);
+  if (IsGrayImage(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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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')
+      {
+        long
+          value;
+
+        value=strtol(q,&q,10);
+      }
+    switch (*q)
+    {
+      case 'd':
+      case 'o':
+      case 'x':
+      {
+        q++;
+        c=(*q);
+        *q='\0';
+        (void) FormatMagickString(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;
+
+        long
+          depth;
+
+        register char
+          *r;
+
+        register long
+          i;
+
+        /*
+          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)));
+  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;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  status=MagickTrue;
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register const IndexPacket
+      *indexes;
+
+    register const PixelPacket
+      *p;
+
+    register long
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,p,indexes+x,&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.matte != MagickFalse)
+        {
+          if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
+              (pixel.opacity != (QuantumAny) pixel.opacity))
+            break;
+        }
+      if (pixel.colorspace == CMYKColorspace)
+        {
+          if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
+              (pixel.index != (QuantumAny) pixel.index))
+            break;
+        }
+      p++;
+    }
+    if (x < (long) 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);
+  AcquireSemaphoreInfo(&(*image)->semaphore);
+  (*image)->reference_count--;
+  RelinquishSemaphoreInfo((*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 unsigned long width,const unsigned long height,
+%        const MagickPixelPacket *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 unsigned long width,const unsigned long height,
+  const MagickPixelPacket *background)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *image;
+
+  long
+    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 MagickPixelPacket *) 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);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetPixelPacket(image,background,q,indexes+x);
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+  }
+  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);
+  (void) LockSemaphoreInfo(image->semaphore);
+  image->reference_count++;
+  (void) 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, OpacityChannel, CyanChannel, MagentaChannel,
+%      YellowChannel, or BlackChannel.
+%
+*/
+MagickExport MagickBooleanType SeparateImageChannel(Image *image,
+  const ChannelType channel)
+{
+#define SeparateImageTag  "Separate/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    switch (channel)
+    {
+      case RedChannel:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->green=q->red;
+          q->blue=q->red;
+          q++;
+        }
+        break;
+      }
+      case GreenChannel:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=q->green;
+          q->blue=q->green;
+          q++;
+        }
+        break;
+      }
+      case BlueChannel:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=q->blue;
+          q->green=q->blue;
+          q++;
+        }
+        break;
+      }
+      case OpacityChannel:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=q->opacity;
+          q->green=q->opacity;
+          q->blue=q->opacity;
+          q++;
+        }
+        break;
+      }
+      case BlackChannel:
+      {
+        if ((image->storage_class != PseudoClass) &&
+            (image->colorspace != CMYKColorspace))
+          break;
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=indexes[x];
+          q->green=indexes[x];
+          q->blue=indexes[x];
+          q++;
+        }
+        break;
+      }
+      case TrueAlphaChannel:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=(Quantum) (QuantumRange-q->opacity);
+          q->green=(Quantum) (QuantumRange-q->opacity);
+          q->blue=(Quantum) (QuantumRange-q->opacity);
+          q++;
+        }
+        break;
+      }
+      case GrayChannels:
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->opacity=(Quantum) (QuantumRange-PixelIntensityToQuantum(q));
+          q++;
+        }
+        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, OpacityChannel, 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 & OpacityChannel) != 0)
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,OpacityChannel);
+      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, ResetAlphaChannel, 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;
+
+      IndexPacket
+        index;
+
+      long
+        y;
+
+      MagickBooleanType
+        status;
+
+      MagickPixelPacket
+        background;
+
+      PixelPacket
+        pixel;
+
+      /*
+        Set transparent pixels to background color.
+      */
+      if (image->matte == MagickFalse)
+        break;
+      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+        break;
+      GetMagickPixelPacket(image,&background);
+      SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
+        NULL,&background);
+      if (image->colorspace == CMYKColorspace)
+        ConvertRGBToCMYK(&background);
+      index=0;
+      SetPixelPacket(image,&background,&pixel,&index);
+      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 < (long) image->rows; y++)
+      {
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (long) image->columns; x++)
+        {
+          if (q->opacity == TransparentOpacity)
+            {
+              q->red=pixel.red;
+              q->green=pixel.green;
+              q->blue=pixel.blue;
+            }
+          q++;
+        }
+        if (image->colorspace == CMYKColorspace)
+          {
+            indexes=GetCacheViewAuthenticIndexQueue(image_view);
+            for (x=0; x < (long) image->columns; x++)
+              indexes[x]=index;
+          }
+        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)
+        {
+          MagickPixelPacket
+            background;
+
+          /*
+            Reset all color channels to background color.
+          */
+          GetMagickPixelPacket(image,&background);
+          SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
+            NULL,&background);
+          (void) LevelImageColors(image,DefaultChannels,&background,&background,
+            MagickTrue);
+        }
+      break;
+    }
+    case ExtractAlphaChannel:
+    {
+      status=SeparateImageChannel(image,TrueAlphaChannel);
+      image->matte=MagickFalse;
+      break;
+    }
+    case ResetAlphaChannel:
+    case OpaqueAlphaChannel:
+    {
+      status=SetImageOpacity(image,OpaqueOpacity);
+      image->matte=MagickTrue;
+      break;
+    }
+    case TransparentAlphaChannel:
+    {
+      status=SetImageOpacity(image,TransparentOpacity);
+      image->matte=MagickTrue;
+      break;
+    }
+    case SetAlphaChannel:
+    {
+      if (image->matte == MagickFalse)
+        {
+          status=SetImageOpacity(image,OpaqueOpacity);
+          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;
+
+  IndexPacket
+    index;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    background;
+
+  PixelPacket
+    pixel;
+
+  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.opacity != OpaqueOpacity)
+    image->matte=MagickTrue;
+  GetMagickPixelPacket(image,&background);
+  SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
+    NULL,&background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  index=0;
+  SetPixelPacket(image,&background,&pixel,&index);
+  /*
+    Set image background color.
+  */
+  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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+      *q++=pixel;
+    if (image->colorspace == CMYKColorspace)
+      {
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        for (x=0; x < (long) image->columns; x++)
+          indexes[x]=index;
+      }
+    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)
+{
+  Cache
+    cache;
+
+  if (image->storage_class == storage_class)
+    return(MagickTrue);
+  image->storage_class=storage_class;
+  cache=GetImagePixelCache(image,MagickTrue,&image->exception);
+  return(cache == (Cache) NULL ? MagickFalse : 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 TransparentOpacity 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 unsigned long columns,const unsigned long 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 unsigned long columns,const unsigned long rows)
+{
+  Cache
+    cache;
+
+  if ((columns != 0) && (rows != 0))
+    {
+      image->columns=columns;
+      image->rows=rows;
+    }
+  cache=GetImagePixelCache(image,MagickTrue,&image->exception);
+  return(cache == (Cache) NULL ? MagickFalse : 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 MagickBooleanType rectify,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info..
+%
+%    o rectify: an unsigned value other than zero rectifies the attribute for
+%      multi-frame support (user may want multi-frame but image format may not
+%      support it).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
+  const MagickBooleanType rectify,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';
+  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
+        {
+          unsigned long
+            first,
+            last;
+
+          (void) CloneString(&image_info->scenes,subimage);
+          image_info->scene=(unsigned long) atol(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=(unsigned long) strtol(p,&q,10);
+            last=first;
+            while (isspace((int) ((unsigned char) *q)) != 0)
+              q++;
+            if (*q == '-')
+              last=(unsigned long) 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;
+          image_info->subimage=image_info->scene;
+          image_info->subrange=image_info->number_scenes;
+        }
+    }
+  *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 long
+        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 (rectify != MagickFalse)
+    {
+      /*
+        Rectify multi-image file support.
+      */
+      (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;
+      magick_info=GetMagickInfo(magic,exception);
+      if (magick_info != (const MagickInfo *) NULL)
+        if (GetMagickAdjoin(magick_info) == MagickFalse)
+          image_info->adjoin=MagickFalse;
+      return(MagickTrue);
+    }
+  if (image_info->affirm != MagickFalse)
+    return(MagickTrue);
+  /*
+    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;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  image->matte=opacity != OpaqueOpacity ? 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 < (long) image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (long) image->columns; x++)
+    {
+      q->opacity=opacity;
+      q++;
+    }
+    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 (IsGrayImage(image,&image->exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace);
+      if (IsMonochromeImage(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 (IsGrayImage(image,&image->exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace);
+      image->matte=MagickFalse;
+      break;
+    }
+    case GrayscaleMatteType:
+    {
+      if (IsGrayImage(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 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) PixelIntensityToQuantum(color_2)-
+    (int) PixelIntensityToQuantum(color_1);
+  return(intensity);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  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 < (long) image->colors; i++)
+    image->colormap[i].opacity=(IndexPacket) 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 < (long) image->colors; i++)
+    pixels[(long) image->colormap[i].opacity]=(unsigned short) i;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    IndexPacket
+      index;
+
+    register long
+      x;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=(IndexPacket) pixels[(long) indexes[x]];
+      indexes[x]=index;
+      *q++=image->colormap[(long) index];
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  pixels=(unsigned short *) RelinquishMagickMemory(pixels);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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");
+  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 IndexPacket PushColormapIndex(Image *image,
+  const unsigned long index,MagickBooleanType *range_exception)
+{
+  if (index < image->colors)
+    return((IndexPacket) index);
+  *range_exception=MagickTrue;
+  return((IndexPacket) 0);
+}
+
+MagickExport MagickBooleanType SyncImage(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    range_exception,
+    status;
+
+  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);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    IndexPacket
+      index;
+
+    PixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=PushColormapIndex(image,(unsigned long) indexes[x],
+        &range_exception);
+      pixel=image->colormap[(long) index];
+      q->red=pixel.red;
+      q->green=pixel.green;
+      q->blue=pixel.blue;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (range_exception != MagickFalse)
+    (void) ThrowMagickException(&image->exception,GetMagickModule(),
+      CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+  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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickStatusType
+    status;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (texture == (const Image *) NULL)
+    return(MagickFalse);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Tile texture onto the image background.
+  */
+  status=MagickTrue;
+  exception=(&image->exception);
+  for (y=0; y < (long) image->rows; y+=texture->rows)
+  {
+    register long
+      x;
+
+    for (x=0; x < (long) image->columns; x+=texture->columns)
+      status|=CompositeImage(image,image->compose,texture,x+
+        texture->tile_offset.x,y+texture->tile_offset.y);
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,TextureImageTag,y,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  (void) SetImageProgress(image,TextureImageTag,image->rows,image->rows);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
diff --git a/magick/image.h b/magick/image.h
new file mode 100644
index 0000000..9a3eaea
--- /dev/null
+++ b/magick/image.h
@@ -0,0 +1,555 @@
+/*
+  Copyright 1999-2009 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 <magick/color.h>
+
+#define OpaqueOpacity  ((Quantum) 0UL)
+#define TransparentOpacity  ((Quantum) QuantumRange)
+
+typedef enum
+{
+  UndefinedAlphaChannel,
+  ActivateAlphaChannel,
+  BackgroundAlphaChannel,
+  CopyAlphaChannel,
+  DeactivateAlphaChannel,
+  ExtractAlphaChannel,
+  OpaqueAlphaChannel,
+  ResetAlphaChannel,  /* deprecated */
+  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 "magick/blob.h"
+#include "magick/colorspace.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/composite.h"
+#include "magick/compress.h"
+#include "magick/effect.h"
+#include "magick/geometry.h"
+#include "magick/layer.h"
+#include "magick/monitor.h"
+#include "magick/pixel.h"
+#include "magick/profile.h"
+#include "magick/quantum.h"
+#include "magick/resample.h"
+#include "magick/resize.h"
+#include "magick/semaphore.h"
+#include "magick/stream.h"
+#include "magick/timer.h"
+
+struct _Image
+{
+  ClassType
+    storage_class;
+
+  ColorspaceType
+    colorspace;
+
+  CompressionType
+    compression;
+
+  unsigned long
+    quality;
+
+  OrientationType
+    orientation;
+
+  MagickBooleanType
+    taint,
+    matte;
+
+  unsigned long
+    columns,
+    rows,
+    depth,
+    colors;
+
+  PixelPacket
+    *colormap,
+    background_color,
+    border_color,
+    matte_color;
+
+  double
+    gamma;
+
+  ChromaticityInfo
+    chromaticity;
+
+  RenderingIntent
+    rendering_intent;
+
+  void
+    *profiles;
+
+  ResolutionType
+    units;
+
+  char
+    *montage,
+    *directory,
+    *geometry;
+
+  long
+    offset;
+
+  double
+    x_resolution,
+    y_resolution;
+
+  RectangleInfo
+    page,
+    extract_info,
+    tile_info;  /* deprecated */
+
+  double
+    bias,
+    blur,  /* deprecated */
+    fuzz;
+
+  FilterTypes
+    filter;
+
+  InterlaceType
+    interlace;
+
+  EndianType
+    endian;
+
+  GravityType
+    gravity;
+
+  CompositeOperator
+    compose;
+
+  DisposeType
+    dispose;
+
+  struct _Image
+    *clip_mask;
+
+  unsigned long
+    scene,
+    delay;
+
+  long
+    ticks_per_second;
+
+  unsigned long
+    iterations,
+    total_colors;
+
+  long
+    start_loop;
+
+  ErrorInfo
+    error;
+
+  TimerInfo
+    timer;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  void
+    *client_data,
+    *cache,
+    *attributes;  /* deprecated */
+
+  Ascii85Info
+    *ascii85;
+
+  BlobInfo
+    *blob;
+
+  char
+    filename[MaxTextExtent],
+    magick_filename[MaxTextExtent],
+    magick[MaxTextExtent];
+
+  unsigned long
+    magick_columns,
+    magick_rows;
+
+  ExceptionInfo
+    exception;
+
+  MagickBooleanType
+    debug;
+
+  volatile long
+    reference_count;
+
+  SemaphoreInfo
+    *semaphore;
+
+  ProfileInfo
+    color_profile,
+    iptc_profile,
+    *generic_profile;
+
+  unsigned long
+    generic_profiles;  /* this & ProfileInfo is deprecated */
+
+  unsigned long
+    signature;
+
+  struct _Image
+    *previous,
+    *list,
+    *next;
+
+  InterpolatePixelMethod
+    interpolate;
+
+  MagickBooleanType
+    black_point_compensation;
+
+  PixelPacket
+    transparent_color;
+
+  struct _Image
+    *mask;
+
+  RectangleInfo
+    tile_offset;
+
+  void
+    *properties,
+    *artifacts;
+
+  ImageType
+    type;
+
+  MagickBooleanType
+    dither;
+};
+
+struct _ImageInfo
+{
+  CompressionType
+    compression;
+
+  OrientationType
+    orientation;
+
+  MagickBooleanType
+    temporary,
+    adjoin,
+    affirm,
+    antialias;
+
+  char
+    *size,
+    *extract,
+    *page,
+    *scenes;
+
+  unsigned long
+    scene,
+    number_scenes,
+    depth;
+
+  InterlaceType
+    interlace;
+
+  EndianType
+    endian;
+
+  ResolutionType
+    units;
+
+  unsigned long
+    quality;
+
+  char
+    *sampling_factor,
+    *server_name,
+    *font,
+    *texture,
+    *density;
+
+  double
+    pointsize,
+    fuzz;
+
+  PixelPacket
+    background_color,
+    border_color,
+    matte_color;
+
+  MagickBooleanType
+    dither,
+    monochrome;
+
+  unsigned long
+    colors;
+
+  ColorspaceType
+    colorspace;
+
+  ImageType
+    type;
+
+  PreviewType
+    preview_type;
+
+  long
+    group;
+
+  MagickBooleanType
+    ping,
+    verbose;
+
+  char
+    *view,
+    *authenticate;
+
+  ChannelType
+    channel;
+
+  Image
+    *attributes;  /* deprecated */
+
+  void
+    *options;
+
+  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;
+
+  char
+    *tile;  /* deprecated */
+
+  unsigned long
+    subimage,  /* deprecated */
+    subrange;  /* deprecated */
+
+  PixelPacket
+    pen;  /* deprecated */
+
+  unsigned long
+    signature;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  PixelPacket
+    transparent_color;
+
+  void
+    *profile;
+
+  MagickBooleanType
+    synchronize;
+};
+
+extern MagickExport ExceptionType
+  CatchImageException(Image *);
+
+extern MagickExport Image
+  *AcquireImage(const ImageInfo *),
+  *AppendImages(const Image *,const MagickBooleanType,ExceptionInfo *),
+  *AverageImages(const Image *,ExceptionInfo *),
+  *CloneImage(const Image *,const unsigned long,const unsigned long,
+    const MagickBooleanType,ExceptionInfo *),
+  *CombineImages(const Image *,const ChannelType,ExceptionInfo *),
+  *DestroyImage(Image *),
+  *GetImageClipMask(const Image *,ExceptionInfo *),
+  *GetImageMask(const Image *,ExceptionInfo *),
+  *NewMagickImage(const ImageInfo *,const unsigned long,const unsigned long,
+    const MagickPixelPacket *),
+  *ReferenceImage(Image *),
+  *SeparateImages(const Image *,const ChannelType,ExceptionInfo *);
+
+extern MagickExport ImageInfo
+  *AcquireImageInfo(void),
+  *CloneImageInfo(const ImageInfo *),
+  *DestroyImageInfo(ImageInfo *);
+
+extern MagickExport ImageType
+  GetImageType(const Image *,ExceptionInfo *);
+
+extern MagickExport long
+  GetImageReferenceCount(Image *);
+
+extern MagickExport MagickBooleanType
+  AcquireImageColormap(Image *,const unsigned long),
+  ClipImage(Image *),
+  ClipImagePath(Image *,const char *,const MagickBooleanType),
+  CycleColormapImage(Image *,const long),
+  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 *),
+  SetImageExtent(Image *,const unsigned long,const unsigned long),
+  SetImageInfo(ImageInfo *,const MagickBooleanType,ExceptionInfo *),
+  SetImageMask(Image *,const Image *),
+  SetImageOpacity(Image *,const Quantum),
+  SetImageStorageClass(Image *,const ClassType),
+  SetImageType(Image *,const ImageType),
+  SortColormapByIntensity(Image *),
+  StripImage(Image *),
+  SyncImage(Image *),
+  TextureImage(Image *,const Image *);
+
+extern MagickExport size_t
+  InterpretImageFilename(const ImageInfo *,Image *,const char *,int,char *);
+
+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/magick/layer.c b/magick/layer.c
new file mode 100644
index 0000000..b7c686b
--- /dev/null
+++ b/magick/layer.c
@@ -0,0 +1,1973 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                     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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/composite.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/profile.h"
+#include "magick/resource_.h"
+#include "magick/resize.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/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;
+
+  long
+    y;
+
+  if (bounds->x < 0)
+    return;
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  exception=(&image->exception);
+  for (y=0; y < (long) bounds->height; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(image,bounds->x,bounds->y+y,bounds->width,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) bounds->width; x++)
+    {
+      q->opacity=(Quantum) TransparentOpacity;
+      q++;
+    }
+    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)
+{
+  long
+    y;
+
+  register long
+    x;
+
+  register const PixelPacket
+    *p,
+    *q;
+
+  if ( bounds->x< 0 ) return(MagickFalse);
+
+  for (y=0; y < (long) 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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    for (x=0; x < (long) bounds->width; x++)
+    {
+      if ((p->opacity <= (long) (QuantumRange/2)) &&
+          (q->opacity > (long) (QuantumRange/2)))
+        break;
+      p++;
+      q++;
+    }
+    if (x < (long) bounds->width)
+      break;
+  }
+  return(y < (long) 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.opacity=(Quantum) TransparentOpacity;
+  (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 ((long) (bounds.x+bounds.width) > (long) coalesce_image->columns)
+      bounds.width=coalesce_image->columns-bounds.x;
+    if (bounds.y < 0)
+      {
+        bounds.height+=bounds.y;
+        bounds.y=0;
+      }
+    if ((long) (bounds.y+bounds.height) > (long) 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
+    *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((Image *) NULL);
+  dispose_image->page=next->page;
+  dispose_image->page.x=0;
+  dispose_image->page.y=0;
+  dispose_image->dispose=NoneDispose;
+  dispose_image->background_color.opacity=(Quantum) TransparentOpacity;
+  (void) SetImageBackgroundColor(dispose_image);
+  dispose_images=NewImageList();
+  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    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,next->matte != MagickFalse ?
+      OverCompositeOp : CopyCompositeOp,next,next->page.x,next->page.y);
+    /*
+      Handle Background dispose: image is displayed for the delay period.
+    */
+    if (next->dispose == BackgroundDispose)
+      {
+        RectangleInfo
+          bounds;
+
+        bounds=next->page;
+        bounds.width=next->columns;
+        bounds.height=next->rows;
+        if (bounds.x < 0)
+          {
+            bounds.width+=bounds.x;
+            bounds.x=0;
+          }
+        if ((long) (bounds.x+bounds.width) > (long) current_image->columns)
+          bounds.width=current_image->columns-bounds.x;
+        if (bounds.y < 0)
+          {
+            bounds.height+=bounds.y;
+            bounds.y=0;
+          }
+        if ((long) (bounds.y+bounds.height) > (long) current_image->rows)
+          bounds.height=current_image->rows-bounds.y;
+        ClearBounds(current_image,&bounds);
+      }
+    /*
+      Select the appropriate previous/disposed image.
+    */
+    if (next->dispose == PreviousDispose)
+      current_image=DestroyImage(current_image);
+    else
+      {
+        dispose_image=DestroyImage(dispose_image);
+        dispose_image=current_image;
+      }
+    {
+      Image
+        *dispose;
+
+      /*
+        Save the dispose image just calculated for return.
+      */
+      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,next);
+      (void) CloneImageProperties(dispose,next);
+      (void) CloneImageArtifacts(dispose,next);
+      dispose->page.x=0;
+      dispose->page.y=0;
+      dispose->dispose=next->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 MagickPixelPacket *p,const MagickPixelPacket *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 MagickPixelPacket *p,const MagickPixelPacket *q)
+{
+  MagickRealType
+    o1,
+    o2;
+
+  /*
+    Any change in pixel values
+  */
+  if (method == CompareAnyLayer)
+    return(IsMagickColorSimilar(p,q) == MagickFalse ? MagickTrue : MagickFalse);
+
+  o1 = (p->matte != MagickFalse) ? p->opacity : OpaqueOpacity;
+  o2 = (q->matte != MagickFalse) ? q->opacity : OpaqueOpacity;
+
+  /*
+    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) (IsMagickColorSimilar(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;
+
+  MagickPixelPacket
+    pixel1,
+    pixel2;
+
+  register const IndexPacket
+    *indexes1,
+    *indexes2;
+
+  register const PixelPacket
+    *p,
+    *q;
+
+  long
+    y;
+
+  register long
+    x;
+
+  /*
+    Set bounding box of the differences between images
+  */
+  GetMagickPixelPacket(image1,&pixel1);
+  GetMagickPixelPacket(image2,&pixel2);
+  for (x=0; x < (long) image1->columns; x++)
+  {
+    p=GetVirtualPixels(image1,x,0,1,image1->rows,exception);
+    q=GetVirtualPixels(image2,x,0,1,image2->rows,exception);
+    if ((p == (const PixelPacket *) NULL) ||
+        (q == (const PixelPacket *) NULL))
+      break;
+    indexes1=GetVirtualIndexQueue(image1);
+    indexes2=GetVirtualIndexQueue(image2);
+    for (y=0; y < (long) image1->rows; y++)
+    {
+      SetMagickPixelPacket(image1,p,indexes1+x,&pixel1);
+      SetMagickPixelPacket(image2,q,indexes2+x,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p++;
+      q++;
+    }
+    if (y < (long) image1->rows)
+      break;
+  }
+  if (x >= (long) 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=(long) 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 PixelPacket *) NULL) ||
+        (q == (const PixelPacket *) NULL))
+      break;
+    indexes1=GetVirtualIndexQueue(image1);
+    indexes2=GetVirtualIndexQueue(image2);
+    for (y=0; y < (long) image1->rows; y++)
+    {
+      SetMagickPixelPacket(image1,p,indexes1+x,&pixel1);
+      SetMagickPixelPacket(image2,q,indexes2+x,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p++;
+      q++;
+    }
+    if (y < (long) image1->rows)
+      break;
+  }
+  bounds.width=(unsigned long) (x-bounds.x+1);
+  for (y=0; y < (long) image1->rows; y++)
+  {
+    p=GetVirtualPixels(image1,0,y,image1->columns,1,exception);
+    q=GetVirtualPixels(image2,0,y,image2->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) ||
+        (q == (const PixelPacket *) NULL))
+      break;
+    indexes1=GetVirtualIndexQueue(image1);
+    indexes2=GetVirtualIndexQueue(image2);
+    for (x=0; x < (long) image1->columns; x++)
+    {
+      SetMagickPixelPacket(image1,p,indexes1+x,&pixel1);
+      SetMagickPixelPacket(image2,q,indexes2+x,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p++;
+      q++;
+    }
+    if (x < (long) image1->columns)
+      break;
+  }
+  bounds.y=y;
+  for (y=(long) 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 PixelPacket *) NULL) ||
+        (q == (const PixelPacket *) NULL))
+      break;
+    indexes1=GetVirtualIndexQueue(image1);
+    indexes2=GetVirtualIndexQueue(image2);
+    for (x=0; x < (long) image1->columns; x++)
+    {
+      SetMagickPixelPacket(image1,p,indexes1+x,&pixel1);
+      SetMagickPixelPacket(image2,q,indexes2+x,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p++;
+      q++;
+    }
+    if (x < (long) image1->columns)
+      break;
+  }
+  bounds.height=(unsigned long) (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 long
+    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.opacity=(Quantum) TransparentOpacity;
+  (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));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D e c o n s t r u c t I m a g e s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeconstructImages() compares each image with the next in a sequence and
+%  returns the minimum bounding region of all differences from the first image.
+%
+%  This function is deprecated in favor of the more universal
+%  CompareImageLayers() function.
+%
+%  The format of the DeconstructImages method is:
+%
+%      Image *DeconstructImages(const Image *images, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *DeconstructImages(const Image *images,
+  ExceptionInfo *exception)
+{
+  return(CompareImageLayers(images,CompareAnyLayer,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     O p t i m i z e L a y e r F r a m e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimizeLayerFrames() 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 animation.
+%
+%  Note that this not easy, and may require the expandsion of the bounds
+%  of previous frame, to clear pixels for the next animation frame,
+%  using GIF Background Dispose method.
+%
+%  Currently this only used internally, with external wrappers below.
+%
+%  The format of the OptimizeLayerFrames method is:
+%
+%      static Image *OptimizeLayerFrames(const Image *image,
+%               const ImageLayerMethod method, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o method: the layers type to optimize with. Must be one of...
+%             OptimizeImageLayer, or  OptimizePlusLayer
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+/*
+  Define a 'fake' dispose method where the frame is duplicated, 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)
+
+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
+    *next;
+
+  register long
+    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
+  */
+  next=GetFirstImageInList(image);
+  for (; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    if ((next->columns != image->columns) || (next->rows != image->rows))
+      ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
+    /*
+      FUTURE: also check they are fully coalesced (full page settings)
+    */
+  }
+  /*
+    Allocate memory (times 2 if we allow frame additions)
+  */
+  next=GetFirstImageInList(image);
+  bounds=(RectangleInfo *) AcquireQuantumMemory((size_t)
+    GetImageListLength(next),(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(next,next->page.width,next->page.height,
+    MagickTrue,exception);
+  if (prev_image == (Image *) NULL)
+    {
+      bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+      disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+      return((Image *) NULL);
+    }
+  prev_image->page=next->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.opacity=(Quantum) TransparentOpacity;
+  (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.
+  */
+  disposals[0]=NoneDispose;
+  bounds[0]=CompareImageBounds(prev_image,next,CompareAnyLayer,exception);
+  /*
+    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;
+  next=GetNextImageInList(next);
+  for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
+  {
+    /*
+      Assume none disposal is the best
+    */
+    bounds[i]=CompareImageBounds(next->previous,next,CompareAnyLayer,exception);
+    cleared=IsBoundsCleared(next->previous,next,&bounds[i],exception);
+    disposals[i-1]=NoneDispose;
+    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,next,CompareAnyLayer,exception);
+        try_cleared=IsBoundsCleared(prev_image,next,&try_bounds,exception);
+        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 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;
+        if ( add_frames )
+          {
+            dup_image=CloneImage(next->previous,next->previous->page.width,
+                next->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,next,CompareClearLayer,exception);
+            ClearBounds(dup_image,&dup_bounds);
+            try_bounds=CompareImageBounds(dup_image,next,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(next->previous,next->previous->page.width,
+          next->previous->page.height,MagickTrue,exception);
+        if (bgnd_image == (Image *) NULL)
+          {
+            bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+            disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+            prev_image=DestroyImage(prev_image);
+            if ( disposals[i-1] == DupDispose )
+              bgnd_image=DestroyImage(bgnd_image);
+            return((Image *) NULL);
+          }
+        bgnd_bounds=bounds[i-1];
+        ClearBounds(bgnd_image,&bgnd_bounds);
+        try_bounds=CompareImageBounds(bgnd_image,next,CompareAnyLayer,exception);
+
+        try_cleared=IsBoundsCleared(bgnd_image,next,&try_bounds,exception);
+        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(prev_image,next,CompareClearLayer,exception);
+            if ( bgnd_bounds.x < 0 )
+              bgnd_bounds = try_bounds;
+            else
+              {
+                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;
+                  }
+              }
+            ClearBounds(bgnd_image,&bgnd_bounds);
+            try_bounds=CompareImageBounds(bgnd_image,next,CompareAnyLayer,exception);
+          }
+        /*
+          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;
+          }
+      }
+    /*
+       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 ( disposals[i-1] != PreviousDispose )
+          prev_image=DestroyImage(prev_image);
+        if ( disposals[i-1] == BackgroundDispose )
+          prev_image=bgnd_image,  bgnd_image=(Image *)NULL;
+        else if (bgnd_image != (Image *) NULL)
+          bgnd_image=DestroyImage(bgnd_image);
+        if ( dup_image != (Image *) NULL)
+          dup_image=DestroyImage(dup_image);
+        if ( disposals[i-1] == NoneDispose )
+          {
+            prev_image=CloneImage(next->previous,next->previous->page.width,
+              next->previous->page.height,MagickTrue,exception);
+            if (prev_image == (Image *) NULL)
+              {
+                bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+                disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+                return((Image *) NULL);
+              }
+          }
+      }
+    disposals[i]=disposals[i-1];
+    i++;
+  }
+  prev_image=DestroyImage(prev_image);
+  /*
+    Optimize all images in sequence.
+  */
+  sans_exception=AcquireExceptionInfo();
+  i=0;
+  next=GetFirstImageInList(image);
+  optimized_image=NewImageList();
+  while ( next != (const Image *) NULL )
+  {
+#if 0 /*  For debuging */
+    printf("image %ld :- %d  %ldx%ld%+ld%+ld\n", i, disposals[i],
+           bounds[i].width, bounds[i].height, bounds[i].x, bounds[i].y );
+#endif
+    prev_image=CloneImage(next,0,0,MagickTrue,exception);
+    if (prev_image == (Image *) NULL)
+      break;
+    if ( disposals[i] == DelDispose ) {
+      unsigned long time = 0;
+      while ( disposals[i] == DelDispose ) {
+        time += next->delay*1000/next->ticks_per_second;
+        next=GetNextImageInList(next);
+        i++;
+      }
+      time += next->delay*1000/next->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
+      next=GetNextImageInList(next);
+    AppendImageToList(&optimized_image,bgnd_image);
+    i++;
+  }
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+  disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+  if (next != (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.opacity=(Quantum) TransparentOpacity;
+  (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 ((long) (bounds.x+bounds.width) > (long) current_image->columns)
+          bounds.width=current_image->columns-bounds.x;
+        if (bounds.y < 0)
+          {
+            bounds.height+=bounds.y;
+            bounds.y=0;
+          }
+        if ((long) (bounds.y+bounds.height) > (long) 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.
+      */
+      unsigned long 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 long x_offset, const long 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,
+     long x_offset, long 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 long x_offset, const long 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 ? */
+    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;
+
+  MagickOffsetType
+    scene;
+
+  RectangleInfo
+    page;
+
+  unsigned long
+    width,
+    height;
+
+  register const Image
+    *next;
+
+  unsigned long
+    number_images;
+
+  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 ( width < (next->page.x + next->columns - page.x) )
+           width = (unsigned long) next->page.x + next->columns - page.x;
+        if ( height < (next->page.y + next->rows - page.y) )
+           height = (unsigned long) next->page.y + 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 ( width < (next->page.x + next->columns) )
+             width = (unsigned long) next->page.x + next->columns;
+          if ( height < (next->page.y + next->rows) )
+             height = (unsigned long) 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 seperatally to normal 'layer merge'
+  */
+  if ( method == TrimBoundsLayer ) {
+    number_images=GetImageListLength(image);
+    for (scene=0; scene < (long) 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,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 < (long) 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,scene,number_images);
+    if (proceed == MagickFalse)
+      break;
+    image=GetNextImageInList(image);
+  }
+  return(canvas);
+}
+
diff --git a/magick/layer.h b/magick/layer.h
new file mode 100644
index 0000000..39c8cd2
--- /dev/null
+++ b/magick/layer.h
@@ -0,0 +1,75 @@
+/*
+  Copyright 1999-2009 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
+
+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 *),
+  *DeconstructImages(const Image *,ExceptionInfo *),
+  *MergeImageLayers(Image *,const ImageLayerMethod,ExceptionInfo *),
+  *OptimizeImageLayers(const Image *,ExceptionInfo *),
+  *OptimizePlusImageLayers(const Image *,ExceptionInfo *);
+
+extern MagickExport void
+  CompositeLayers(Image *,const CompositeOperator,Image *,const long,const long,
+    ExceptionInfo *),
+  OptimizeImageTransparency(const Image *,ExceptionInfo *),
+  RemoveDuplicateLayers(Image **,ExceptionInfo *),
+  RemoveZeroDelayLayers(Image **,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/list.c b/magick/list.c
new file mode 100644
index 0000000..f0b9898
--- /dev/null
+++ b/magick/list.c
@@ -0,0 +1,1295 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                         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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/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;
+  SyncImageList(*images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long
+    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 == 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 long
+    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 < (long) 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=first; i <= last; i++)
+      if ((i >= 0) && (i < (long) length))
+        delete_list[i]=MagickTrue;
+  }
+  /*
+    Delete images marked for deletion, once only
+  */
+  image=(*images);
+  for (i=0; i < (long) 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long 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 long index)
+{
+  long
+    offset;
+
+  register const Image
+    *p;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  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+=(long) length) ;
+  for (i=0; p != (Image *) NULL; p=p->next)
+    if (i++ == (long) (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:
+%
+%      long GetImageIndexInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport long GetImageIndexInList(const Image *images)
+{
+  register long
+    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:
+%
+%      unsigned long GetImageListLength(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport unsigned long GetImageListLength(const Image *images)
+{
+  register long
+    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((unsigned long) 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 long
+    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 immediatally 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. Old image is destroyed.
+%  The given image list pointer is set to point to the just inserted image.
+%
+%  The format of the ReplaceImageInList method is:
+%
+%      ReplaceImageInList(Image **images,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o image: the image.
+%
+*/
+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);
+  image->next=(*images)->next;
+  if (image->next != (Image *) NULL)
+    image->next->previous=image;
+  image->previous=(*images)->previous;
+  if (image->previous != (Image *) NULL)
+    image->previous->next=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 unsigned long,
+%        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 unsigned long length,const Image *splice)
+{
+  Image
+    *image,
+    *split;
+
+  register unsigned long
+    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->endian=images->endian;
+  return(images->next);
+}
diff --git a/magick/list.h b/magick/list.h
new file mode 100644
index 0000000..69550d6
--- /dev/null
+++ b/magick/list.h
@@ -0,0 +1,63 @@
+/*
+  Copyright 1999-2009 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 *),
+  *GetFirstImageInList(const Image *),
+  *GetImageFromList(const Image *,const long),
+  *GetLastImageInList(const Image *),
+  *GetNextImageInList(const Image *),
+  *GetPreviousImageInList(const Image *),
+  **ImageListToArray(const Image *,ExceptionInfo *),
+  *NewImageList(void),
+  *RemoveImageFromList(Image **),
+  *RemoveLastImageFromList(Image **),
+  *RemoveFirstImageFromList(Image **),
+  *SpliceImageIntoList(Image **,const unsigned long,const Image *),
+  *SplitImageList(Image *),
+  *SyncNextImageInList(const Image *);
+
+extern MagickExport long
+  GetImageIndexInList(const Image *);
+
+extern MagickExport unsigned long
+  GetImageListLength(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 *),
+  ReverseImageList(Image **),
+  SyncImageList(Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/locale.c b/magick/locale.c
new file mode 100644
index 0000000..cacf4e7
--- /dev/null
+++ b/magick/locale.c
@@ -0,0 +1,1057 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define LocaleFilename  "locale.xml"
+#define MaxRecursionDepth  200
+
+/*
+  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;
+
+static volatile MagickBooleanType
+  instantiate_locale = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeLocaleList(ExceptionInfo *),
+  LoadLocaleLists(const char *,const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y L o c a l e L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyLocaleList() deallocates memory associated with the locale list.
+%
+%  The format of the DestroyLocaleList method is:
+%
+%      DestroyLocaleList(void)
+%
+*/
+MagickExport void DestroyLocaleList(void)
+{
+  AcquireSemaphoreInfo(&locale_semaphore);
+  if (locale_list != (SplayTreeInfo *) NULL)
+    locale_list=DestroySplayTree(locale_list);
+  instantiate_locale=MagickFalse;
+  RelinquishSemaphoreInfo(locale_semaphore);
+  DestroySemaphoreInfo(&locale_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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,
+%        unsigned long *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,
+  unsigned long *number_messages,ExceptionInfo *exception)
+{
+  const LocaleInfo
+    **messages;
+
+  register const LocaleInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate locale list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_messages != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(locale_semaphore);
+  qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
+  messages[i]=(LocaleInfo *) NULL;
+  *number_messages=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_messages,ExceptionInfo *exception)
+{
+  char
+    **messages;
+
+  register const LocaleInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate locale list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_messages != (unsigned long *) NULL);
+  *number_messages=0;
+  p=GetLocaleInfo_("*",exception);
+  if (p == (const LocaleInfo *) NULL)
+    return((char **) NULL);
+  AcquireSemaphoreInfo(&locale_semaphore);
+  RelinquishSemaphoreInfo(locale_semaphore);
+  messages=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
+  if (messages == (char **) NULL)
+    return((char **) NULL);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(locale_semaphore);
+  qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
+  messages[i]=(char *) NULL;
+  *number_messages=(unsigned long) 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) FormatMagickString(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) FormatMagickString(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(__WINDOWS__)
+  {
+    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))
+    {
+      AcquireSemaphoreInfo(&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;
+        }
+      RelinquishSemaphoreInfo(locale_semaphore);
+    }
+  return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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 long
+    i;
+
+  unsigned long
+    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 < (long) 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) fprintf(file,"\nPath: %s\n\n",locale_info[i]->path);
+        (void) fprintf(file,"Tag/Message\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=locale_info[i]->path;
+    (void) fprintf(file,"%s\n",locale_info[i]->tag);
+    if (locale_info[i]->message != (char *) NULL)
+      (void) fprintf(file,"  %s",locale_info[i]->message);
+    (void) fprintf(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 unsigned long 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 unsigned long components)
+{
+  long
+    count;
+
+  register char
+    *p;
+
+  if (*path == '\0')
+    return;
+  p=path+strlen(path)-1;
+  if (*p == '/')
+    *p='\0';
+  for (count=0; (count < (long) components) && (p > path); p--)
+    if (*p == '/')
+      {
+        *p='\0';
+        count++;
+      }
+  if (count < (long) 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 MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
+  const char *locale,const unsigned long depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    message[MaxTextExtent],
+    tag[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  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)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  locale_info=(LocaleInfo *) NULL;
+  *tag='\0';
+  *message='\0';
+  *keyword='\0';
+  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);
+  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
+}
diff --git a/magick/locale_.h b/magick/locale_.h
new file mode 100644
index 0000000..d1919cb
--- /dev/null
+++ b/magick/locale_.h
@@ -0,0 +1,69 @@
+/*
+  Copyright 1999-2009 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 "magick/hashmap.h"
+
+typedef struct _LocaleInfo
+{
+  char
+    *path,
+    *tag,
+    *message;
+                                                                                
+  MagickBooleanType
+    stealth;
+                                                                                
+  struct _LocaleInfo
+    *previous,
+    *next;  /* deprecated, use GetLocaleInfoList() */
+
+  unsigned long
+    signature;
+} LocaleInfo;
+
+extern MagickExport char
+  **GetLocaleList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetLocaleMessage(const char *);
+
+extern MagickExport const LocaleInfo
+  *GetLocaleInfo_(const char *,ExceptionInfo *),
+  **GetLocaleInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport LinkedListInfo
+  *DestroyLocaleOptions(LinkedListInfo *),
+  *GetLocaleOptions(const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListLocaleInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyLocaleList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/log.c b/magick/log.c
new file mode 100644
index 0000000..502c711
--- /dev/null
+++ b/magick/log.c
@@ -0,0 +1,1681 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                             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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/semaphore.h"
+#include "magick/timer.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/thread_.h"
+#include "magick/thread-private.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#include "magick/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;
+
+  unsigned long
+    generations,
+    limit;
+
+  FILE
+    *file;
+
+  unsigned long
+    generation;
+
+  MagickBooleanType
+    append,
+    stealth;
+
+  TimerInfo
+    timer;
+
+  unsigned long
+    signature;
+};
+
+/*
+  Declare log map.
+*/
+static const HandlerInfo
+  LogHandlers[] =
+  {
+    { "console", ConsoleHandler },
+    { "debug", DebugHandler },
+    { "event", EventHandler },
+    { "file", FileHandler },
+    { "none", NoHandler },
+    { "stderr", StderrHandler },
+    { "stdout", StdoutHandler },
+    { (char *) NULL, UndefinedHandler }
+  };
+
+static const char
+  *LogMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<logmap>"
+    "  <log events=\"None\" />"
+    "  <log output=\"console\" />"
+    "  <log filename=\"Magick-%d.log\" />"
+    "  <log format=\"%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n  %e\" />"
+    "</logmap>";
+
+/*
+  Static declarations.
+*/
+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);
+  AcquireSemaphoreInfo(&log_semaphore);
+  if (log_info->file != (FILE *) NULL)
+    {
+      if (log_info->append == MagickFalse)
+        (void) fprintf(log_info->file,"</log>\n");
+      (void) fclose(log_info->file);
+      log_info->file=(FILE *) NULL;
+    }
+  RelinquishSemaphoreInfo(log_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y L o g L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyLogList() deallocates memory associated with the log list.
+%
+%  The format of the DestroyLogList method is:
+%
+%      DestroyLogList(void)
+%
+*/
+
+static void *DestroyLogElement(void *log_info)
+{
+  register LogInfo
+    *p;
+
+  p=(LogInfo *) log_info;
+  if (p->file != (FILE *) NULL)
+    {
+      if (p->append == MagickFalse)
+        (void) fprintf(p->file,"</log>\n");
+      (void) fclose(p->file);
+      p->file=(FILE *) NULL;
+    }
+  if (p->filename != (char *) NULL)
+    p->filename=DestroyString(p->filename);
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  if (p->format != (char *) NULL)
+    p->format=DestroyString(p->format);
+  p=(LogInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void DestroyLogList(void)
+{
+  AcquireSemaphoreInfo(&log_semaphore);
+  if (log_list != (LinkedListInfo *) NULL)
+    log_list=DestroyLinkedList(log_list,DestroyLogElement);
+  instantiate_log=MagickFalse;
+  RelinquishSemaphoreInfo(log_semaphore);
+  DestroySemaphoreInfo(&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.
+  */
+  AcquireSemaphoreInfo(&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));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_preferences,ExceptionInfo *exception)
+{
+  const LogInfo
+    **preferences;
+
+  register const LogInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate log list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_preferences != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(log_semaphore);
+  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
+  preferences[i]=(LogInfo *) NULL;
+  *number_preferences=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_preferences,ExceptionInfo *exception)
+{
+  char
+    **preferences;
+
+  register const LogInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate log list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_preferences != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(log_semaphore);
+  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
+  preferences[i]=(char *) NULL;
+  *number_preferences=(unsigned long) 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))
+    {
+      AcquireSemaphoreInfo(&log_semaphore);
+      if ((log_list == (LinkedListInfo *) NULL) &&
+          (instantiate_log == MagickFalse))
+        {
+          (void) LoadLogLists(LogFilename,exception);
+          instantiate_log=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_aliases;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",log_info[i]->path);
+        (void) fprintf(file,"Filename       Generations     Limit  Format\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=log_info[i]->path;
+    if (log_info[i]->filename != (char *) NULL)
+      {
+        (void) fprintf(file,"%s",log_info[i]->filename);
+        for (j=(long) strlen(log_info[i]->filename); j <= 16; j++)
+          (void) fprintf(file," ");
+      }
+    (void) fprintf(file,"%9lu  ",log_info[i]->generations);
+    (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),limit);
+    (void) fprintf(file,"%8s  ",limit);
+    if (log_info[i]->format != (char *) NULL)
+      (void) fprintf(file,"%s",log_info[i]->format);
+    (void) fprintf(file,"\n");
+  }
+  (void) fflush(file);
+  log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long 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 unsigned long 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) FormatMagickString(text,extent,
+        "<entry>\n"
+        "  <timestamp>%s</timestamp>\n"
+        "  <elapsed-time>%ld:%02ld</elapsed-time>\n"
+        "  <user-time>%0.3f</user-time>\n"
+        "  <process-id>%ld</process-id>\n"
+        "  <thread-id>%lu</thread-id>\n"
+        "  <module>%s</module>\n"
+        "  <function>%s</function>\n"
+        "  <line>%lu</line>\n"
+        "  <domain>%s</domain>\n"
+        "  <event>%s</event>\n"
+        "</entry>",timestamp,(long) (elapsed_time/60.0),
+        (long) ceil(fmod(elapsed_time,60.0)),user_time,(long) getpid(),
+        GetMagickThreadSignature(),module,function,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+=FormatMagickString(q,extent,"%lu",log_info->generation %
+          log_info->generations);
+        break;
+      }
+      case 'l':
+      {
+        q+=FormatMagickString(q,extent,"%lu",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+=FormatMagickString(q,extent,"%ld",(long) getpid());
+        break;
+      }
+      case 'r':
+      {
+        q+=FormatMagickString(q,extent,"%ld:%02ld",(long)
+          (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)));
+        break;
+      }
+      case 't':
+      {
+        q+=FormatMagickTime(seconds,extent,q);
+        break;
+      }
+      case 'u':
+      {
+        q+=FormatMagickString(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+=FormatMagickString(q,extent,"%lu",log_info->generation %
+          log_info->generations);
+        break;
+      }
+      case 'n':
+      {
+        q+=CopyMagickString(q,GetLogName(),extent);
+        break;
+      }
+      case 'p':
+      {
+        q+=FormatMagickString(q,extent,"%ld",(long) 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 unsigned long 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);
+  AcquireSemaphoreInfo(&log_semaphore);
+  if ((log_info->event_mask & type) == 0)
+    {
+      RelinquishSemaphoreInfo(log_semaphore);
+      return(MagickTrue);
+    }
+  domain=MagickOptionToMnemonic(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);
+      RelinquishSemaphoreInfo(log_semaphore);
+      return(MagickFalse);
+    }
+  if ((log_info->handler_mask & ConsoleHandler) != 0)
+    {
+      (void) fprintf(stderr,"%s\n",text);
+      (void) fflush(stderr);
+    }
+  if ((log_info->handler_mask & DebugHandler) != 0)
+    {
+#if defined(__WINDOWS__)
+      OutputDebugString(text);
+#endif
+    }
+  if ((log_info->handler_mask & EventHandler) != 0)
+    {
+#if defined(__WINDOWS__)
+      (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 > (off_t) (1024*1024*log_info->limit))
+        {
+          (void) fprintf(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);
+              RelinquishSemaphoreInfo(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)
+            {
+              RelinquishSemaphoreInfo(log_semaphore);
+              return(MagickFalse);
+            }
+          log_info->generation++;
+          if (log_info->append == MagickFalse)
+            {
+              (void) fprintf(log_info->file,"<?xml version=\"1.0\" "
+                "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
+              (void) fprintf(log_info->file,"<log>\n");
+            }
+        }
+      (void) fprintf(log_info->file,"%s\n",text);
+      (void) fflush(log_info->file);
+    }
+  if ((log_info->handler_mask & StdoutHandler) != 0)
+    {
+      (void) fprintf(stdout,"%s\n",text);
+      (void) fflush(stdout);
+    }
+  if ((log_info->handler_mask & StderrHandler) != 0)
+    {
+      (void) fprintf(stderr,"%s\n",text);
+      (void) fflush(stderr);
+    }
+  text=(char  *) RelinquishMagickMemory(text);
+  (void) ContinueTimer((TimerInfo *) &log_info->timer);
+  RelinquishSemaphoreInfo(log_semaphore);
+  return(MagickTrue);
+}
+
+MagickBooleanType LogMagickEvent(const LogEventType type,const char *module,
+  const char *function,const unsigned long 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 unsigned long 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 unsigned long 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->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 |
+              ParseMagickOption(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=(unsigned long) atol(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=(unsigned long) atol(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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadLogList(LogMap,"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|=LoadLogList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((log_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(log_list) != MagickFalse))
+    status|=LoadLogList(LogMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 long
+    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;
+
+  long
+    option;
+
+  exception=AcquireExceptionInfo();
+  log_info=(LogInfo *) GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  option=ParseMagickOption(MagickLogEventOptions,MagickTrue,events);
+  AcquireSemaphoreInfo(&log_semaphore);
+  log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
+  log_info->event_mask=(LogEventType) option;
+  if (option == -1)
+    log_info->event_mask=UndefinedEvents;
+  RelinquishSemaphoreInfo(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);
+  AcquireSemaphoreInfo(&log_semaphore);
+  if (log_info->format != (char *) NULL)
+    log_info->format=DestroyString(log_info->format);
+  log_info->format=ConstantString(format);
+  RelinquishSemaphoreInfo(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/magick/log.h b/magick/log.h
new file mode 100644
index 0000000..87705ee
--- /dev/null
+++ b/magick/log.h
@@ -0,0 +1,93 @@
+/*
+  Copyright 1999-2009 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 "magick/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,
+  LocaleEvent = 0x00200,
+  ModuleEvent = 0x00400,
+  PolicyEvent = 0x00800,
+  ResourceEvent = 0x01000,
+  TransformEvent = 0x02000,
+  UserEvent = 0x04000,
+  WandEvent = 0x08000,
+  X11Event = 0x10000,
+  AllEvents = 0x7fffffff
+} LogEventType;
+
+typedef struct _LogInfo
+  LogInfo;
+
+extern MagickExport char
+  **GetLogList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetLogName(void),
+  *SetLogName(const char *);
+                                                                                
+extern MagickExport const LogInfo
+  **GetLogInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport LogEventType
+  SetLogEventMask(const char *);
+
+extern MagickExport MagickBooleanType
+  IsEventLogging(void),
+  ListLogInfo(FILE *,ExceptionInfo *),
+  LogMagickEvent(const LogEventType,const char *,const char *,
+    const unsigned long,const char *,...) 
+    magick_attribute((format (printf,5,6))),
+  LogMagickEventList(const LogEventType,const char *,const char *,
+    const unsigned long,const char *,va_list)
+    magick_attribute((format (printf,5,0)));
+
+extern MagickExport void
+  CloseMagickLog(void),
+  DestroyLogList(void),
+  SetLogFormat(const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/mac.c b/magick/mac.c
new file mode 100644
index 0000000..9849907
--- /dev/null
+++ b/magick/mac.c
@@ -0,0 +1,1607 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                            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-2009 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, [email protected].  The Ghostscript launch code is strongly
+%  based on Dave Schooley's Mac Gnuplot and contributed by
+%  [email protected].  Mac-centric improvements contributed by
+%  [email protected].
+%
+%
+*/
+
+#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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/quantum.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/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)
+
+  long
+    size;
+
+  Ptr
+    data;
+
+  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;
+
+  long
+    version;
+
+  Rect
+    rectangle;
+
+  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) fprintf(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,
+  unsigned long *free_bytes,unsigned long *total_bytes)
+{
+  HParamBlockRec
+    pb;
+
+  OSErr
+    result;
+
+  unsigned long
+    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=(unsigned long) 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)
+{
+  unsigned long
+    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) FormatMagickString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatMagickString(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) FormatMagickString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatMagickString(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,long 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(long 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(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) FormatMagickString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatMagickString(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 [email protected]
+%  (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;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  PicHandle
+    picture_handle;
+
+  PictInfo
+    picture_info;
+
+  QDErr
+    theErr = noErr;
+
+  Rect
+    rectangle;
+
+  RGBColor
+    Pixel;
+
+  short
+    colormap_id;
+
+  /*
+    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))
+    {
+      unsigned long
+        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 IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    indexes=GetAuthenticIndexQueue(image);
+    for (x=0; x < image->columns; x++)
+    {
+      GetCPixel(x,y,&Pixel);
+      q->red=ScaleCharToQuantum(Pixel.red & 0xff);
+      q->green=ScaleCharToQuantum(Pixel.green & 0xff);
+      q->blue=ScaleCharToQuantum(Pixel.blue & 0xff);
+      if (image->storage_class == PseudoClass)
+        indexes[x]=Color2Index(&Pixel);
+      q++;
+    }
+    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;
+
+  long
+    buffer_size = 16384;
+
+  OSErr
+    error;
+
+  ProcessInfoRec
+    application_info;
+
+  ProcessSerialNumber
+    serial_number;
+
+  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,long 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,long 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 long telldir(DIR *entry)
+{
+  return(entry->d_index);
+}
+#endif
+
+#endif
diff --git a/magick/mac.h b/magick/mac.h
new file mode 100644
index 0000000..16ac282
--- /dev/null
+++ b/magick/mac.h
@@ -0,0 +1,111 @@
+/*
+  Copyright 1999-2009 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 int
+    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/magick/magic.c b/magick/magic.c
new file mode 100644
index 0000000..271a055
--- /dev/null
+++ b/magick/magic.c
@@ -0,0 +1,954 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                    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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/magic.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MagicFilename  "magic.xml"
+
+/*
+  Static declarations.
+*/
+static const char
+  *MagicMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<magicmap>"
+    "  <magic name=\"AVI\" offset=\"0\" target=\"RIFF\" />"
+    "  <magic name=\"8BIMWTEXT\" offset=\"0\" target=\"8\\000B\\000I\\000M\\000#\" />"
+    "  <magic name=\"8BIMTEXT\" offset=\"0\" target=\"8BIM#\" />"
+    "  <magic name=\"8BIM\" offset=\"0\" target=\"8BIM\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"BA\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"BM\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"CI\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"CP\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"IC\" />"
+    "  <magic name=\"BMP\" offset=\"0\" target=\"PI\" />"
+    "  <magic name=\"CIN\" offset=\"0\" target=\"\\200\\052\\137\\327\" />"
+    "  <magic name=\"CGM\" offset=\"0\" target=\"BEGMF\" />"
+    "  <magic name=\"DCM\" offset=\"128\" target=\"DICM\" />"
+    "  <magic name=\"DCX\" offset=\"0\" target=\"\\261\\150\\336\\72\" />"
+    "  <magic name=\"DDS\" offset=\"0\" target=\"DDS \" />"
+    "  <magic name=\"DIB\" offset=\"0\" target=\"\\050\\000\" />"
+    "  <magic name=\"DJVU\" offset=\"0\" target=\"AT&TFORM\" />"
+    "  <magic name=\"DOT\" offset=\"0\" target=\"digraph\" />"
+    "  <magic name=\"DPX\" offset=\"0\" target=\"SDPX\" />"
+    "  <magic name=\"DPX\" offset=\"0\" target=\"XPDS\" />"
+    "  <magic name=\"EMF\" offset=\"40\" target=\"\\040\\105\\115\\106\\000\\000\\001\\000\" />"
+    "  <magic name=\"EPT\" offset=\"0\" target=\"\\305\\320\\323\\306\" />"
+    "  <magic name=\"EXR\" offset=\"0\" target=\"\\166\\057\\061\\001\" />"
+    "  <magic name=\"FAX\" offset=\"0\" target=\"DFAX\" />"
+    "  <magic name=\"FIG\" offset=\"0\" target=\"#FIG\" />"
+    "  <magic name=\"FITS\" offset=\"0\" target=\"IT0\" />"
+    "  <magic name=\"FITS\" offset=\"0\" target=\"SIMPLE\" />"
+    "  <magic name=\"FPX\" offset=\"0\" target=\"\\320\\317\\021\\340\" />"
+    "  <magic name=\"GIF\" offset=\"0\" target=\"GIF8\" />"
+    "  <magic name=\"GPLT\" offset=\"0\" target=\"#!/usr/local/bin/gnuplot\" />"
+    "  <magic name=\"HDF\" offset=\"1\" target=\"HDF\" />"
+    "  <magic name=\"HPGL\" offset=\"0\" target=\"IN;\" />"
+    "  <magic name=\"HTML\" offset=\"1\" target=\"HTML\" />"
+    "  <magic name=\"HTML\" offset=\"1\" target=\"html\" />"
+    "  <magic name=\"ILBM\" offset=\"8\" target=\"ILBM\" />"
+    "  <magic name=\"IPTCWTEXT\" offset=\"0\" target=\"\\062\\000#\\000\\060\\000=\\000\\042\\000&\\000#\\000\\060\\000;\\000&\\000#\\000\\062\\000;\\000\\042\\000\" />"
+    "  <magic name=\"IPTCTEXT\" offset=\"0\" target=\"2#0=\\042&#0;&#2;\\042\" />"
+    "  <magic name=\"IPTC\" offset=\"0\" target=\"\\034\\002\" />"
+    "  <magic name=\"JNG\" offset=\"0\" target=\"\\213JNG\\r\\n\\032\\n\" />"
+    "  <magic name=\"JPEG\" offset=\"0\" target=\"\\377\\330\\377\" />"
+    "  <magic name=\"JPC\" offset=\"0\" target=\"\\377\\117\" />"
+    "  <magic name=\"JP2\" offset=\"4\" target=\"\\152\\120\\040\\040\\015\" />"
+    "  <magic name=\"MIFF\" offset=\"0\" target=\"Id=ImageMagick\" />"
+    "  <magic name=\"MIFF\" offset=\"0\" target=\"id=ImageMagick\" />"
+    "  <magic name=\"MNG\" offset=\"0\" target=\"\\212MNG\\r\\n\\032\\n\" />"
+    "  <magic name=\"MPC\" offset=\"0\" target=\"id=MagickCache\" />"
+    "  <magic name=\"MPEG\" offset=\"0\" target=\"\\000\\000\\001\\263\" />"
+    "  <magic name=\"MVG\" offset=\"0\" target=\"push graphic-context\" />"
+    "  <magic name=\"PCD\" offset=\"2048\" target=\"PCD_\" />"
+    "  <magic name=\"PCL\" offset=\"0\" target=\"\\033E\\033\" />"
+    "  <magic name=\"PCX\" offset=\"0\" target=\"\\012\\002\" />"
+    "  <magic name=\"PCX\" offset=\"0\" target=\"\\012\\005\" />"
+    "  <magic name=\"PDB\" offset=\"60\" target=\"vIMGView\" />"
+    "  <magic name=\"PDF\" offset=\"0\" target=\"%PDF-\" />"
+    "  <magic name=\"PFA\" offset=\"0\" target=\"%!PS-AdobeFont-1.0\" />"
+    "  <magic name=\"PFB\" offset=\"6\" target=\"%!PS-AdobeFont-1.0\" />"
+    "  <magic name=\"PGX\" offset=\"0\" target=\"\\050\\107\\020\\115\\046\" />"
+    "  <magic name=\"PICT\" offset=\"522\" target=\"\\000\\021\\002\\377\\014\\000\" />"
+    "  <magic name=\"PNG\" offset=\"0\" target=\"\\211PNG\\r\\n\\032\\n\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P1\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P2\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P3\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P4\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P5\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P6\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"P7\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"PF\" />"
+    "  <magic name=\"PNM\" offset=\"0\" target=\"Pf\" />"
+    "  <magic name=\"PS\" offset=\"0\" target=\"%!\" />"
+    "  <magic name=\"PS\" offset=\"0\" target=\"\\004%!\" />"
+    "  <magic name=\"PS\" offset=\"0\" target=\"\\305\\320\\323\\306\" />"
+    "  <magic name=\"PSD\" offset=\"0\" target=\"8BPS\" />"
+    "  <magic name=\"PWP\" offset=\"0\" target=\"SFW95\" />"
+    "  <magic name=\"RAD\" offset=\"0\" target=\"#?RADIANCE\" />"
+    "  <magic name=\"RAD\" offset=\"0\" target=\"VIEW= \" />"
+    "  <magic name=\"RLE\" offset=\"0\" target=\"\\122\\314\" />"
+    "  <magic name=\"SCT\" offset=\"0\" target=\"CT\" />"
+    "  <magic name=\"SFW\" offset=\"0\" target=\"SFW94\" />"
+    "  <magic name=\"SGI\" offset=\"0\" target=\"\\001\\332\" />"
+    "  <magic name=\"SUN\" offset=\"0\" target=\"\\131\\246\\152\\225\" />"
+    "  <magic name=\"SVG\" offset=\"1\" target=\"?XML\" />"
+    "  <magic name=\"SVG\" offset=\"1\" target=\"?xml\" />"
+    "  <magic name=\"TXT\" offset=\"0\" target=\"# ImageMagick pixel enumeration:\" />"
+    "  <magic name=\"TIFF\" offset=\"0\" target=\"\\115\\115\\000\\052\" />"
+    "  <magic name=\"TIFF\" offset=\"0\" target=\"\\111\\111\\052\\000\" />"
+    "  <magic name=\"TIFF64\" offset=\"0\" target=\"\\115\\115\\000\\053\\000\\010\\000\\000\" />"
+    "  <magic name=\"TIFF64\" offset=\"0\" target=\"\\115\\115\\000\\053\\000\\010\\000\\000\" />"
+    "  <magic name=\"VICAR\" offset=\"0\" target=\"LBLSIZE\" />"
+    "  <magic name=\"VICAR\" offset=\"0\" target=\"NJPL1I\" />"
+    "  <magic name=\"VIFF\" offset=\"0\" target=\"\\253\\001\" />"
+    "  <magic name=\"WMF\" offset=\"0\" target=\"\\327\\315\\306\\232\" />"
+    "  <magic name=\"WMF\" offset=\"0\" target=\"\\001\\000\\011\\000\" />"
+    "  <magic name=\"WPG\" offset=\"0\" target=\"\\377WPC\" />"
+    "  <magic name=\"XBM\" offset=\"0\" target=\"#define\" />"
+    "  <magic name=\"XCF\" offset=\"0\" target=\"gimp xcf\" />"
+    "  <magic name=\"XPM\" offset=\"1\" target=\"* XPM *\" />"
+    "  <magic name=\"XWD\" offset=\"4\" target=\"\\007\\000\\000\" />"
+    "  <magic name=\"XWD\" offset=\"5\" target=\"\\000\\000\\007\" />"
+    "</magicmap>";
+
+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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M a g i c L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagicList() deallocates memory associated with the magic list.
+%
+%  The format of the DestroyMagicList method is:
+%
+%      DestroyMagicList(void)
+%
+*/
+
+static void *DestroyMagicElement(void *magic_info)
+{
+  register MagicInfo
+    *p;
+
+  p=(MagicInfo *) magic_info;
+  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 DestroyMagicList(void)
+{
+  AcquireSemaphoreInfo(&magic_semaphore);
+  if (magic_list != (LinkedListInfo *) NULL)
+    magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
+  instantiate_magic=MagickFalse;
+  RelinquishSemaphoreInfo(magic_semaphore);
+  DestroySemaphoreInfo(&magic_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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.
+  */
+  AcquireSemaphoreInfo(&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));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_aliases,ExceptionInfo *exception)
+{
+  const MagicInfo
+    **aliases;
+
+  register const MagicInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate magic list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (unsigned long *) NULL);
+  *number_aliases=0;
+  p=GetMagicInfo((const unsigned char *) "*",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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(magic_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
+  aliases[i]=(MagicInfo *) NULL;
+  *number_aliases=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_aliases,ExceptionInfo *exception)
+{
+  char
+    **aliases;
+
+  register const MagicInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (unsigned long *) NULL);
+  *number_aliases=0;
+  p=GetMagicInfo((const unsigned char *) "*",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);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(magic_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
+  aliases[i]=(char *) NULL;
+  *number_aliases=(unsigned long) 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))
+    {
+      AcquireSemaphoreInfo(&magic_semaphore);
+      if ((magic_list == (LinkedListInfo *) NULL) &&
+          (instantiate_magic == MagickFalse))
+        {
+          (void) LoadMagicLists(MagicFilename,exception);
+          instantiate_magic=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_aliases;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",magic_info[i]->path);
+        (void) fprintf(file,"Name      Offset Target\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=magic_info[i]->path;
+    (void) fprintf(file,"%s",magic_info[i]->name);
+    for (j=(long) strlen(magic_info[i]->name); j <= 9; j++)
+      (void) fprintf(file," ");
+    (void) fprintf(file,"%6ld ",(long) magic_info[i]->offset);
+    if (magic_info[i]->target != (char *) NULL)
+      (void) fprintf(file,"%s",magic_info[i]->target);
+    (void) fprintf(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 unsigned long 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 unsigned long 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);
+  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->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) atol(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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadMagicList(MagicMap,"built-in",0,exception));
+#else
+  char
+    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|=LoadMagicList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((magic_list == (LinkedListInfo *) NULL) || 
+      (IsLinkedListEmpty(magic_list) != MagickFalse))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ConfigureWarning,
+        "UnableToOpenConfigureFile","`%s'",path);
+      status|=LoadMagicList(MagicMap,"built-in",0,exception);
+    }
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
diff --git a/magick/magic.h b/magick/magic.h
new file mode 100644
index 0000000..6c94021
--- /dev/null
+++ b/magick/magic.h
@@ -0,0 +1,72 @@
+/*
+  Copyright 1999-2009 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
+    stealth;
+
+  struct _MagicInfo
+    *previous,
+    *next;  /* deprecated, use GetMagicInfoList() */
+
+  unsigned long
+    signature;
+} MagicInfo;
+
+extern MagickExport char
+  **GetMagicList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetMagicName(const MagicInfo *);
+
+extern MagickExport MagickBooleanType
+  ListMagicInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport const MagicInfo
+  *GetMagicInfo(const unsigned char *,const size_t,ExceptionInfo *),
+  **GetMagicInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyMagicList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/magick-config.h b/magick/magick-config.h
new file mode 100644
index 0000000..4e53c87
--- /dev/null
+++ b/magick/magick-config.h
@@ -0,0 +1,1340 @@
+#ifndef _MAGICK_MAGICK_CONFIG_H
+#define _MAGICK_MAGICK_CONFIG_H 1
+ 
+/* magick/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. */
+#ifndef MAGICKCORE_BUILD_MODULES 
+#define MAGICKCORE_BUILD_MODULES  1 
+#endif
+
+/* 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.5.5/modules-Q16/coders/" 
+#endif
+
+/* Subdirectory of lib where coder modules are installed */
+#ifndef MAGICKCORE_CODER_RELATIVE_PATH 
+#define MAGICKCORE_CODER_RELATIVE_PATH  "ImageMagick-6.5.5/modules-Q16/coders" 
+#endif
+
+/* Directory where architecture-dependent configuration files live. */
+#ifndef MAGICKCORE_CONFIGURE_PATH 
+#define MAGICKCORE_CONFIGURE_PATH  "/usr/local/lib/ImageMagick-6.5.5/config/" 
+#endif
+
+/* Subdirectory of lib where architecture-dependent configuration files live.
+   */
+#ifndef MAGICKCORE_CONFIGURE_RELATIVE_PATH 
+#define MAGICKCORE_CONFIGURE_RELATIVE_PATH  "ImageMagick-6.5.5/config" 
+#endif
+
+/* Define if you have DJVU library */
+#ifndef MAGICKCORE_DJVU_DELEGATE 
+#define MAGICKCORE_DJVU_DELEGATE  1 
+#endif
+
+/* Directory where ImageMagick documents live. */
+#ifndef MAGICKCORE_DOCUMENTATION_PATH 
+#define MAGICKCORE_DOCUMENTATION_PATH  "/usr/local/share/doc/ImageMagick-6.5.5/" 
+#endif
+
+/* Define if you have Display Postscript */
+/* #undef DPS_DELEGATE */
+
+/* Build self-contained, embeddable, zero-configuration ImageMagick
+   (experimental) */
+/* #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 */
+#ifndef MAGICKCORE_FFTW_DELEGATE 
+#define MAGICKCORE_FFTW_DELEGATE  1 
+#endif
+
+/* Location of filter modules */
+#ifndef MAGICKCORE_FILTER_PATH 
+#define MAGICKCORE_FILTER_PATH  "/usr/local/lib/ImageMagick-6.5.5/modules-Q16/filters/" 
+#endif
+
+/* Subdirectory of lib where filter modules are installed */
+#ifndef MAGICKCORE_FILTER_RELATIVE_PATH 
+#define MAGICKCORE_FILTER_RELATIVE_PATH  "ImageMagick-6.5.5/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 */
+/* #undef GVC_DELEGATE */
+
+/* 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 if bool is a built-in type */
+#ifndef MAGICKCORE_HAVE_BOOL 
+#define MAGICKCORE_HAVE_BOOL  /**/ 
+#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 the `clock_gettime' function. */
+#ifndef MAGICKCORE_HAVE_CLOCK_GETTIME 
+#define MAGICKCORE_HAVE_CLOCK_GETTIME  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 <complex.h> header file. */
+#ifndef MAGICKCORE_HAVE_COMPLEX_H 
+#define MAGICKCORE_HAVE_COMPLEX_H  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 `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 <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. */
+/* #undef HAVE_FLOOR */
+
+/* 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 `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 `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 you have the <inttypes.h> header file. */
+#ifndef MAGICKCORE_HAVE_INTTYPES_H 
+#define MAGICKCORE_HAVE_INTTYPES_H  1 
+#endif
+
+/* Define if you have the <lcms.h> header file. */
+#ifndef MAGICKCORE_HAVE_LCMS_H 
+#define MAGICKCORE_HAVE_LCMS_H  1 
+#endif
+
+/* 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 <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 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 you have the `lstat' function. */
+#ifndef MAGICKCORE_HAVE_LSTAT 
+#define MAGICKCORE_HAVE_LSTAT  1 
+#endif
+
+/* define if the compiler implements L"widestring" */
+#ifndef MAGICKCORE_HAVE_LSTRING 
+#define MAGICKCORE_HAVE_LSTRING  /**/ 
+#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 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 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 `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 `pow' function. */
+/* #undef HAVE_POW */
+
+/* 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 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 `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 `sqrt' function. */
+/* #undef HAVE_SQRT */
+
+/* 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 <stddef.h> header file. */
+#ifndef MAGICKCORE_HAVE_STDDEF_H 
+#define MAGICKCORE_HAVE_STDDEF_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 if the compiler supports the std namespace */
+#ifndef MAGICKCORE_HAVE_STD_NAMESPACE 
+#define MAGICKCORE_HAVE_STD_NAMESPACE  /**/ 
+#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 `strtol' function. */
+#ifndef MAGICKCORE_HAVE_STRTOL 
+#define MAGICKCORE_HAVE_STRTOL  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/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 you have the <unistd.h> header file. */
+#ifndef MAGICKCORE_HAVE_UNISTD_H 
+#define MAGICKCORE_HAVE_UNISTD_H  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 `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 `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 `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
+
+/* 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 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 */
+
+/* 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 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.5.5/" 
+#endif
+
+/* Subdirectory of lib where ImageMagick architecture dependent files are
+   installed */
+#ifndef MAGICKCORE_LIBRARY_RELATIVE_PATH 
+#define MAGICKCORE_LIBRARY_RELATIVE_PATH  "ImageMagick-6.5.5" 
+#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/xulrunner-1.9.1" 
+#endif
+
+/* The archive extension */
+#ifndef MAGICKCORE_LT_LIBEXT 
+#define MAGICKCORE_LT_LIBEXT  "a" 
+#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 to prepend to default font search path. */
+/* #undef MAGICK_FONT_PATH */
+
+/* Magick API method prefix */
+/* #undef NAMESPACE_PREFIX */
+
+/* Turn off assert statements */
+/* #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 6.5.5" 
+#endif
+
+/* Define to the one symbol short name of this package. */
+#ifndef MAGICKCORE_PACKAGE_TARNAME 
+#define MAGICKCORE_PACKAGE_TARNAME  "ImageMagick" 
+#endif
+
+/* Define to the version of this package. */
+#ifndef MAGICKCORE_PACKAGE_VERSION 
+#define MAGICKCORE_PACKAGE_VERSION  "6.5.5" 
+#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 */
+#ifndef MAGICKCORE_RSVG_DELEGATE 
+#define MAGICKCORE_RSVG_DELEGATE  1 
+#endif
+
+/* 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_CONFIGURE_PATH 
+#define MAGICKCORE_SHARE_CONFIGURE_PATH  "/usr/local/share/ImageMagick-6.5.5/config/" 
+#endif
+
+/* Subdirectory of lib where architecture-independent configuration files
+   live. */
+#ifndef MAGICKCORE_SHARE_CONFIGURE_RELATIVE_PATH 
+#define MAGICKCORE_SHARE_CONFIGURE_RELATIVE_PATH  "ImageMagick-6.5.5/config" 
+#endif
+
+/* Directory where architecture-independent files live. */
+#ifndef MAGICKCORE_SHARE_PATH 
+#define MAGICKCORE_SHARE_PATH  "/usr/local/share/ImageMagick-6.5.5/" 
+#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 `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 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 to use the Windows GDI32 library */
+/* #undef WINGDI32_DELEGATE */
+
+/* Define if using the dmalloc debugging malloc package */
+/* #undef WITH_DMALLOC */
+
+/* Define if you have wmflite library */
+#ifndef MAGICKCORE_WMFLITE_DELEGATE 
+#define MAGICKCORE_WMFLITE_DELEGATE  1 
+#endif
+
+/* 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. */
+#ifndef MAGICKCORE__FILE_OFFSET_BITS 
+#define MAGICKCORE__FILE_OFFSET_BITS  64 
+#endif
+
+/* 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 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 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 empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to a type to use for `error_t' if it is not otherwise available. */
+/* #undef error_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 `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, even
+   though the corresponding Sun C compiler does, which causes
+   "#define restrict _Restrict" in the previous line.  Perhaps some future
+   version of Sun C++ will work with _Restrict; if so, it'll probably
+   define __RESTRICT, just as Sun C does.  */
+#if defined __SUNPRO_CC && !defined __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 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: _MAGICK_MAGICK_CONFIG_H */
+#endif
diff --git a/magick/magick-type.h b/magick/magick-type.h
new file mode 100644
index 0000000..5bdee39
--- /dev/null
+++ b/magick/magick-type.h
@@ -0,0 +1,189 @@
+/*
+  Copyright 1999-2009 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 "magick/magick-config.h"
+
+#if !defined(MAGICKCORE_QUANTUM_DEPTH)
+#define MAGICKCORE_QUANTUM_DEPTH  16
+#endif
+
+#if defined(__WINDOWS__) && !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  255UL
+#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  65535UL
+#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  4294967295UL
+#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;
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+typedef double Quantum;
+#define QuantumRange  18446744073709551615.0
+#define QuantumFormat  "%g"
+#else
+typedef unsigned long long Quantum;
+#define QuantumRange  MagickULLConstant(18446744073709551615)
+#define QuantumFormat  "%llu"
+#endif
+#else
+#if !defined(_CH_)
+# error "Specified value of MAGICKCORE_QUANTUM_DEPTH is not supported"
+#endif
+#endif
+#define MaxRGB  QuantumRange  /* deprecated */
+
+/*
+  Typedef declarations.
+*/
+typedef unsigned int MagickStatusType;
+#if !defined(__WINDOWS__)
+#if (MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG == 8)
+typedef long long MagickOffsetType;
+typedef unsigned long long MagickSizeType;
+#define MagickSizeFormat  "%10llu"
+#else
+typedef long MagickOffsetType;
+typedef unsigned long MagickSizeType;
+#define MagickSizeFormat  "%10lu"
+#endif
+#else
+typedef __int64 MagickOffsetType;
+typedef unsigned __int64 MagickSizeType;
+#define MagickSizeFormat  "%10llu"
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER == 1200)
+typedef MagickOffsetType QuantumAny;
+#else
+typedef MagickSizeType QuantumAny;
+#endif
+
+#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,
+  MatteChannel = 0x0008,  /* deprecated */
+  BlackChannel = 0x0020,
+  IndexChannel = 0x0020,
+  AllChannels = 0x002F,
+  /* special 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/magick/magick.c b/magick/magick.c
new file mode 100644
index 0000000..61b4ae7
--- /dev/null
+++ b/magick/magick.c
@@ -0,0 +1,1440 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/coder.h"
+#include "magick/client.h"
+#include "magick/coder.h"
+#include "magick/configure.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/mime.h"
+#include "magick/module.h"
+#if defined(__WINDOWS__)
+# include "magick/nt-feature.h"
+#endif
+#include "magick/random_.h"
+#include "magick/registry.h"
+#include "magick/resource_.h"
+#include "magick/policy.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/thread_.h"
+#include "magick/thread-private.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/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;  /* double-checked locking pattern */
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeMagickList(ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M a g i c k L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagickList() deallocates memory associated with the MagickInfo list.
+%
+%  The format of the DestroyMagickList method is:
+%
+%      void DestroyMagickList(void)
+%
+*/
+MagickExport void DestroyMagickList(void)
+{
+  AcquireSemaphoreInfo(&magick_semaphore);
+  if (magick_list != (SplayTreeInfo *) NULL)
+    magick_list=DestroySplayTree(magick_list);
+  instantiate_magick=MagickFalse;
+  RelinquishSemaphoreInfo(magick_semaphore);
+  DestroySemaphoreInfo(&magick_semaphore);
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  UnregisterStaticModules();
+#endif
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  DestroyModuleList();
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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;
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(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
+      AcquireSemaphoreInfo(&magick_semaphore);
+      ResetSplayTreeIterator(magick_list);
+      p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+      RelinquishSemaphoreInfo(magick_semaphore);
+      return(p);
+    }
+  /*
+    Find name in list.
+  */
+  AcquireSemaphoreInfo(&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
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_formats,ExceptionInfo *exception)
+{
+  const MagickInfo
+    **formats;
+
+  register const MagickInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate magick list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_formats != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(magick_semaphore);
+  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickInfoCompare);
+  formats[i]=(MagickInfo *) NULL;
+  *number_formats=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_formats,ExceptionInfo *exception)
+{
+  char
+    **formats;
+
+  register const MagickInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate magick list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_formats != (unsigned long *) 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);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(magick_semaphore);
+  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickCompare);
+  formats[i]=(char *) NULL;
+  *number_formats=(unsigned long) i;
+  return(formats);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k E n d i a n 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)
+{
+  if ((magick_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_magick == MagickFalse))
+    {
+      AcquireSemaphoreInfo(&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;
+        }
+      RelinquishSemaphoreInfo(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 is not a valid
+%  image format or 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)
+{
+  const DelegateInfo
+    *delegate_info;
+
+  const MagickInfo
+    *magick_info;
+
+  ExceptionInfo
+    *exception;
+
+  assert(magick != (char *) NULL);
+  exception=AcquireExceptionInfo();
+  magick_info=GetMagickInfo(magick,exception);
+  delegate_info=GetDelegateInfo(magick,(char *) NULL,exception);
+  if (delegate_info == (const DelegateInfo *) NULL)
+    delegate_info=GetDelegateInfo((char *) NULL,magick,exception);
+  exception=DestroyExceptionInfo(exception);
+  if ((magick_info == (const MagickInfo *) NULL) &&
+      (delegate_info == (const DelegateInfo *) NULL))
+    return(MagickTrue);
+#if defined(macintosh)
+  return(MACIsMagickConflict(magick));
+#elif defined(vms)
+  return(VMSIsMagickConflict(magick));
+#elif defined(__WINDOWS__)
+  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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_formats;
+
+  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) fprintf(file,"   Format  Mode  Description\n");
+#else
+  (void) fprintf(file,"   Format  Module    Mode  Description\n");
+#endif
+  (void) fprintf(file,"--------------------------------------------------------"
+    "-----------------------\n");
+  for (i=0; i < (long) number_formats; i++)
+  {
+    if (magick_info[i]->stealth != MagickFalse)
+      continue;
+    (void) fprintf(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) fprintf(file,"%9s ",module);
+    }
+#endif
+    (void) fprintf(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) fprintf(file,"  %s",magick_info[i]->description);
+    if (magick_info[i]->version != (char *) NULL)
+      (void) fprintf(file," (%s)",magick_info[i]->version);
+    (void) fprintf(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) fprintf(file,"           %s\n",text[j]);
+              text[j]=DestroyString(text[j]);
+            }
+            text=(char **) RelinquishMagickMemory(text);
+          }
+      }
+  }
+  (void) fprintf(file,"\n* native blob support\n");
+  (void) fprintf(file,"r read support\n");
+  (void) fprintf(file,"w write support\n");
+  (void) fprintf(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 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
+  AsynchronousDestroyMagickResources();
+  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(MAGICKCORE_HAVE__EXIT)
+  exit(signal_number);
+#else
+#if defined(SIGHUP)
+  if (signal_number == SIGHUP)
+    exit(signal_number);
+#endif
+#if defined(SIGINT) && !defined(__WINDOWS__)
+  if (signal_number == SIGINT)
+    exit(signal_number);
+#endif
+#if defined(SIGTERM)
+  if (signal_number == SIGTERM)
+    exit(signal_number);
+#endif
+  _exit(signal_number);
+#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];
+
+  ExceptionInfo
+    *exception;
+
+  time_t
+    seconds;
+
+  /*
+    Initialize the Magick environment.
+  */
+  (void) setlocale(LC_ALL,"");
+  (void) setlocale(LC_NUMERIC,"C");
+  InitializeSemaphore();
+  seconds=time((time_t *) NULL);
+  events=GetEnvironmentValue("MAGICK_DEBUG");
+  if (events != (char *) NULL)
+    {
+      (void) SetLogEventMask(events);
+      events=DestroyString(events);
+    }
+#if defined(__WINDOWS__)
+#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(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(__WINDOWS__)
+      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
+    }
+  /*
+    Initialize magick resources.
+  */
+  InitializeMagickResources();
+  exception=AcquireExceptionInfo();
+  (void) GetMagickInfo((char *) NULL,exception);
+  exception=DestroyExceptionInfo(exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 DestroyMagick function is:
+%
+%      MagickCoreTerminus(void)
+%
+*/
+MagickExport void MagickCoreTerminus(void)
+{
+#if defined(MAGICKCORE_X11_DELEGATE)
+  DestroyXResources();
+#endif
+  DestroyConstitute();
+  DestroyMimeList();
+  DestroyConfigureList();
+  DestroyTypeList();
+  DestroyColorList();
+#if defined(__WINDOWS__)
+  NTGhostscriptUnLoadDLL();
+#endif
+  DestroyMagicList();
+  DestroyDelegateList();
+  DestroyMagickList();
+  DestroyCoderList();
+  DestroyMagickResources();
+  DestroyImageRegistry();
+  DestroyPixelCacheResources();
+  DestroyPolicyList();
+  DestroyRandomReservoir();
+  DestroyLocaleList();
+  DestroyLogList();
+  instantiate_magick=MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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);
+  AcquireSemaphoreInfo(&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);
+  RelinquishSemaphoreInfo(magick_semaphore);
+  return(status);
+}
diff --git a/magick/magick.h b/magick/magick.h
new file mode 100644
index 0000000..af44c3a
--- /dev/null
+++ b/magick/magick.h
@@ -0,0 +1,138 @@
+/*
+  Copyright 1999-2009 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;
+
+  struct _MagickInfo
+    *previous,
+    *next;  /* deprecated, use GetMagickInfoList() */
+
+  unsigned long
+    signature;
+} MagickInfo;
+
+extern MagickExport char
+  **GetMagickList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetMagickDescription(const MagickInfo *);
+
+extern MagickExport DecodeImageHandler
+  *GetImageDecoder(const MagickInfo *);
+
+extern MagickExport EncodeImageHandler
+  *GetImageEncoder(const MagickInfo *);
+
+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),
+  UnregisterMagickInfo(const char *);
+
+extern const MagickExport MagickInfo
+  *GetMagickInfo(const char *,ExceptionInfo *),
+  **GetMagickInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport MagickInfo
+  *RegisterMagickInfo(MagickInfo *),
+  *SetMagickInfo(const char *);
+
+extern MagickExport MagickStatusType
+  GetMagickThreadSupport(const MagickInfo *);
+
+extern MagickExport void
+  DestroyMagickList(void),
+  MagickCoreGenesis(const char *,const MagickBooleanType),
+  MagickCoreTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/matrix.c b/magick/matrix.c
new file mode 100644
index 0000000..ddb29a1
--- /dev/null
+++ b/magick/matrix.c
@@ -0,0 +1,418 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/matrix.h"
+#include "magick/memory_.h"
+#include "magick/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 dimentional 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 unsigned long nptrs,
+%           const unsigned long size)
+%
+%  A description of each parameter follows:
+%
+%    o nptrs: 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 unsigned long nptrs,
+     const unsigned long size)
+{
+  double
+   **matrix;
+
+  register unsigned long
+    i,
+    j;
+
+  matrix=(double **) AcquireQuantumMemory(nptrs,sizeof(*matrix));
+  if (matrix == (double **) NULL)
+    return((double **)NULL);
+
+  for (i=0; i < nptrs; 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);
+    }
+    /*(void) ResetMagickMemory(matrix[i],0,size*sizeof(*matrix[i])); */
+    for (j=0; j < 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 unsigned long rank, const unsigned long nvecs)
+%
+%  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 nvecs: 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 unsigned long rank, const unsigned long nvecs)
+{
+#define GaussJordanSwap(x,y) \
+{ \
+  if ((x) != (y)) \
+    { \
+      (x)+=(y); \
+      (y)=(x)-(y); \
+      (x)=(x)-(y); \
+    } \
+}
+
+  double
+    max,
+    scale;
+
+  long
+    column,
+    *columns,
+    *pivots,
+    row,
+    *rows;
+
+  register long
+    i,
+    j,
+    k;
+
+  columns=(long *) AcquireQuantumMemory(rank,sizeof(*columns));
+  rows=(long *) AcquireQuantumMemory(rank,sizeof(*rows));
+  pivots=(long *) AcquireQuantumMemory(rank,sizeof(*pivots));
+  if ((rows == (long *) NULL) || (columns == (long *) NULL) ||
+      (pivots == (long *) NULL))
+    {
+      if (pivots != (long *) NULL)
+        pivots=(long *) RelinquishMagickMemory(pivots);
+      if (columns != (long *) NULL)
+        columns=(long *) RelinquishMagickMemory(columns);
+      if (rows != (long *) NULL)
+        rows=(long *) 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 < (long) rank; i++)
+  {
+    max=0.0;
+    for (j=0; j < (long) rank; j++)
+      if (pivots[j] != 1)
+        {
+          for (k=0; k < (long) 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 < (long) rank; k++)
+          GaussJordanSwap(matrix[row][k],matrix[column][k]);
+        for (k=0; k < (long) nvecs; 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 < (long) rank; j++)
+      matrix[column][j]*=scale;
+    for (j=0; j < (long) nvecs; j++)
+      vectors[j][column]*=scale;
+    for (j=0; j < (long) rank; j++)
+      if (j != column)
+        {
+          scale=matrix[j][column];
+          matrix[j][column]=0.0;
+          for (k=0; k < (long) rank; k++)
+            matrix[j][k]-=scale*matrix[column][k];
+          for (k=0; k < (long) nvecs; k++)
+            vectors[k][j]-=scale*vectors[k][column];
+        }
+  }
+  for (j=(long) rank-1; j >= 0; j--)
+    if (columns[j] != rows[j])
+      for (i=0; i < (long) rank; i++)
+        GaussJordanSwap(matrix[i][rows[j]],matrix[i][columns[j]]);
+  pivots=(long *) RelinquishMagickMemory(pivots);
+  rows=(long *) RelinquishMagickMemory(rows);
+  columns=(long *) 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 unsigned long rank, const unsigned long nvecs);
+%
+%  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 nvecs: 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 dimentional 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 unsigned long rank,
+     const unsigned long nvecs)
+{
+  register unsigned long
+    i,
+    j;
+
+  for(j=0; j<rank; j++) {
+    for(i=0; i<rank; i++)
+      matrix[i][j] += terms[i] * terms[j];
+    for(i=0; i<nvecs; 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 unsigned long nptrs)
+%
+%  A description of each parameter follows:
+%
+%    o matrix: the matrix to relinquish
+%
+%    o nptrs: the first dimention of the acquired matrix (number of pointers)
+%
+*/
+MagickExport double **RelinquishMagickMatrix(double **matrix,
+     const unsigned long nptrs)
+{
+  register unsigned long
+    i;
+
+  if (matrix == (double **) NULL )
+    return(matrix);
+
+  for (i=0; i < nptrs; i++)
+     matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
+  matrix=(double **) RelinquishMagickMemory(matrix);
+
+  return(matrix);
+}
+
diff --git a/magick/matrix.h b/magick/matrix.h
new file mode 100644
index 0000000..0984d96
--- /dev/null
+++ b/magick/matrix.h
@@ -0,0 +1,41 @@
+/*
+  Copyright 1999-2009 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 unsigned long,const unsigned long),
+  **RelinquishMagickMatrix(double **,const unsigned long);
+
+extern MagickExport MagickBooleanType
+  GaussJordanElimination(double **,double **,const unsigned long,
+       const unsigned long);
+
+extern MagickExport void
+  LeastSquaresAddTerms(double **,double **,const double *,const double *,
+       const unsigned long, const unsigned long);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/memory.c b/magick/memory.c
new file mode 100644
index 0000000..077b5f8
--- /dev/null
+++ b/magick/memory.c
@@ -0,0 +1,975 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/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 = { malloc, realloc, 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.
+%
+*/
+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,size) == 0)
+      return(memory);
+  }
+#endif
+  return(malloc(size));
+}
+
+#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 (free_segments == (DataSegmentInfo *) NULL)
+    {
+      AcquireSemaphoreInfo(&memory_semaphore);
+      if (free_segments == (DataSegmentInfo *) NULL)
+        {
+          register long
+            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]);
+        }
+      RelinquishSemaphoreInfo(memory_semaphore);
+    }
+  AcquireSemaphoreInfo(&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);
+    }
+  RelinquishSemaphoreInfo(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 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 long
+    i;
+
+  AcquireSemaphoreInfo(&memory_semaphore);
+  RelinquishSemaphoreInfo(memory_semaphore);
+  for (i=0; i < (long) 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 long
+    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=(long) 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);
+  AcquireSemaphoreInfo(&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)));
+  RelinquishSemaphoreInfo(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
+  AcquireSemaphoreInfo(&memory_semaphore);
+  block=ResizeBlock(memory,size == 0 ? 1UL : size);
+  if (block == (void *) NULL)
+    {
+      if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
+        {
+          RelinquishSemaphoreInfo(memory_semaphore);
+          memory=RelinquishMagickMemory(memory);
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        }
+      block=ResizeBlock(memory,size == 0 ? 1UL : size);
+      assert(block != (void *) NULL);
+    }
+  RelinquishSemaphoreInfo(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/magick/memory_.h b/magick/memory_.h
new file mode 100644
index 0000000..8cf6cca
--- /dev/null
+++ b/magick/memory_.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2009 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),
+  *AcquireMagickMemory(const size_t),
+  *AcquireQuantumMemory(const size_t,const size_t),
+  *CopyMagickMemory(void *,const void *,const size_t),
+  DestroyMagickMemory(void),
+  GetMagickMemoryMethods(AcquireMemoryHandler *,ResizeMemoryHandler *,
+    DestroyMemoryHandler *),
+  *RelinquishAlignedMemory(void *),
+  *RelinquishMagickMemory(void *),
+  *ResetMagickMemory(void *,int,const size_t),
+  *ResizeMagickMemory(void *,const size_t),
+  *ResizeQuantumMemory(void *,const size_t,const size_t),
+  SetMagickMemoryMethods(AcquireMemoryHandler,ResizeMemoryHandler,
+    DestroyMemoryHandler);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/methods.h b/magick/methods.h
new file mode 100644
index 0000000..b62d342
--- /dev/null
+++ b/magick/methods.h
@@ -0,0 +1,1367 @@
+/*
+  Copyright 1999-2009 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 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 AcquirePixelCacheInfo  PrependMagickMethod(AcquirePixelCacheInfo)
+#define AcquirePixelCacheNexus  PrependMagickMethod(AcquirePixelCacheNexus)
+#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 AsynchronousDestroyMagickResources  PrependMagickMethod(AsynchronousDestroyMagickResources)
+#define AttachBlob  PrependMagickMethod(AttachBlob)
+#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 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 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 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 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 ConfigureFileToStringInfo  PrependMagickMethod(ConfigureFileToStringInfo)
+#define ConsolidateCMYKImages  PrependMagickMethod(ConsolidateCMYKImages)
+#define ConstantString  PrependMagickMethod(ConstantString)
+#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 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 DestroyCoderList  PrependMagickMethod(DestroyCoderList)
+#define DestroyColorList  PrependMagickMethod(DestroyColorList)
+#define DestroyConfigureList  PrependMagickMethod(DestroyConfigureList)
+#define DestroyConfigureOptions  PrependMagickMethod(DestroyConfigureOptions)
+#define DestroyConstitute  PrependMagickMethod(DestroyConstitute)
+#define DestroyDelegateList  PrependMagickMethod(DestroyDelegateList)
+#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 DestroyImageRegistry  PrependMagickMethod(DestroyImageRegistry)
+#define DestroyImages  PrependMagickMethod(DestroyImages)
+#define DestroyLinkedList  PrependMagickMethod(DestroyLinkedList)
+#define DestroyLocaleList  PrependMagickMethod(DestroyLocaleList)
+#define DestroyLocaleOptions  PrependMagickMethod(DestroyLocaleOptions)
+#define DestroyLogList  PrependMagickMethod(DestroyLogList)
+#define DestroyMagickList  PrependMagickMethod(DestroyMagickList)
+#define DestroyMagickMemory  PrependMagickMethod(DestroyMagickMemory)
+#define DestroyMagick  PrependMagickMethod(DestroyMagick)
+#define DestroyMagickRegistry  PrependMagickMethod(DestroyMagickRegistry)
+#define DestroyMagickResources  PrependMagickMethod(DestroyMagickResources)
+#define DestroyMagicList  PrependMagickMethod(DestroyMagicList)
+#define DestroyMimeList  PrependMagickMethod(DestroyMimeList)
+#define DestroyMontageInfo  PrependMagickMethod(DestroyMontageInfo)
+#define DestroyPixelCache  PrependMagickMethod(DestroyPixelCache)
+#define DestroyPixelCacheNexus  PrependMagickMethod(DestroyPixelCacheNexus)
+#define DestroyPixelCacheResources  PrependMagickMethod(DestroyPixelCacheResources)
+#define DestroyPolicyList  PrependMagickMethod(DestroyPolicyList)
+#define DestroyQuantizeInfo  PrependMagickMethod(DestroyQuantizeInfo)
+#define DestroyQuantumInfo  PrependMagickMethod(DestroyQuantumInfo)
+#define DestroyRandomInfo  PrependMagickMethod(DestroyRandomInfo)
+#define DestroyRandomReservoir  PrependMagickMethod(DestroyRandomReservoir)
+#define DestroyResampleFilter  PrependMagickMethod(DestroyResampleFilter)
+#define DestroyResizeFilter  PrependMagickMethod(DestroyResizeFilter)
+#define DestroySemaphoreInfo  PrependMagickMethod(DestroySemaphoreInfo)
+#define DestroySemaphore  PrependMagickMethod(DestroySemaphore)
+#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 DestroyTypeList  PrependMagickMethod(DestroyTypeList)
+#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 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 FormatMagickStringList  PrependMagickMethod(FormatMagickStringList)
+#define FormatMagickString  PrependMagickMethod(FormatMagickString)
+#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 GetAuthenticIndexQueue  PrependMagickMethod(GetAuthenticIndexQueue)
+#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 GetCacheViewAuthenticIndexQueue  PrependMagickMethod(GetCacheViewAuthenticIndexQueue)
+#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 GetCacheViewVirtualIndexQueue  PrependMagickMethod(GetCacheViewVirtualIndexQueue)
+#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 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 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 GetMagickGeometry  PrependMagickMethod(GetMagickGeometry)
+#define GetMagickHomeURL  PrependMagickMethod(GetMagickHomeURL)
+#define GetMagickInfoList  PrependMagickMethod(GetMagickInfoList)
+#define GetMagickInfo  PrependMagickMethod(GetMagickInfo)
+#define GetMagickList  PrependMagickMethod(GetMagickList)
+#define GetMagickMemoryMethods  PrependMagickMethod(GetMagickMemoryMethods)
+#define GetMagickOptions  PrependMagickMethod(GetMagickOptions)
+#define GetMagickPackageName  PrependMagickMethod(GetMagickPackageName)
+#define GetMagickPixelPacket  PrependMagickMethod(GetMagickPixelPacket)
+#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 GetPixelCacheNexusIndexes  PrependMagickMethod(GetPixelCacheNexusIndexes)
+#define GetPixelCacheNexusPixels  PrependMagickMethod(GetPixelCacheNexusPixels)
+#define GetPixelCacheStorageClass  PrependMagickMethod(GetPixelCacheStorageClass)
+#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 GetVirtualIndexesFromNexus  PrependMagickMethod(GetVirtualIndexesFromNexus)
+#define GetVirtualIndexQueue  PrependMagickMethod(GetVirtualIndexQueue)
+#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 Huffman2DEncodeImage  PrependMagickMethod(Huffman2DEncodeImage)
+#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 InitializeMagickResources  PrependMagickMethod(InitializeMagickResources)
+#define InitializeSemaphore  PrependMagickMethod(InitializeSemaphore)
+#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 IsColorSimilar  PrependMagickMethod(IsColorSimilar)
+#define IsEventLogging  PrependMagickMethod(IsEventLogging)
+#define IsGeometry  PrependMagickMethod(IsGeometry)
+#define IsGlob  PrependMagickMethod(IsGlob)
+#define IsGrayImage  PrependMagickMethod(IsGrayImage)
+#define IsHashmapEmpty  PrependMagickMethod(IsHashmapEmpty)
+#define IsHighDynamicRangeImage  PrependMagickMethod(IsHighDynamicRangeImage)
+#define IsHistogramImage  PrependMagickMethod(IsHistogramImage)
+#define IsImageObject  PrependMagickMethod(IsImageObject)
+#define IsImagesEqual  PrependMagickMethod(IsImagesEqual)
+#define IsImageSimilar  PrependMagickMethod(IsImageSimilar)
+#define IsLinkedListEmpty  PrependMagickMethod(IsLinkedListEmpty)
+#define IsMagickColorSimilar  PrependMagickMethod(IsMagickColorSimilar)
+#define IsMagickConflict  PrependMagickMethod(IsMagickConflict)
+#define IsMagickInstantiated  PrependMagickMethod(IsMagickInstantiated)
+#define IsMagickOption  PrependMagickMethod(IsMagickOption)
+#define IsMagickTrue  PrependMagickMethod(IsMagickTrue)
+#define IsMonochromeImage  PrependMagickMethod(IsMonochromeImage)
+#define IsOpacitySimilar  PrependMagickMethod(IsOpacitySimilar)
+#define IsOpaqueImage  PrependMagickMethod(IsOpaqueImage)
+#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 LeastSquaresAddTerms  PrependMagickMethod(LeastSquaresAddTerms)
+#define LevelImageChannel  PrependMagickMethod(LevelImageChannel)
+#define LevelImageColors  PrependMagickMethod(LevelImageColors)
+#define LevelImage  PrependMagickMethod(LevelImage)
+#define LevelizeImageChannel  PrependMagickMethod(LevelizeImageChannel)
+#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 ListMagickOptions  PrependMagickMethod(ListMagickOptions)
+#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 LocaleLower  PrependMagickMethod(LocaleLower)
+#define LocaleNCompare  PrependMagickMethod(LocaleNCompare)
+#define LocaleUpper  PrependMagickMethod(LocaleUpper)
+#define LockSemaphoreInfo  PrependMagickMethod(LockSemaphoreInfo)
+#define LogMagickEventList  PrependMagickMethod(LogMagickEventList)
+#define LogMagickEvent  PrependMagickMethod(LogMagickEvent)
+#define LZWEncodeImage  PrependMagickMethod(LZWEncodeImage)
+#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 MagickOptionToMnemonic  PrependMagickMethod(MagickOptionToMnemonic)
+#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 MinifyImage  PrependMagickMethod(MinifyImage)
+#define ModifyImage  PrependMagickMethod(ModifyImage)
+#define ModulateImage  PrependMagickMethod(ModulateImage)
+#define MontageImageList  PrependMagickMethod(MontageImageList)
+#define MontageImages  PrependMagickMethod(MontageImages)
+#define MorphImages  PrependMagickMethod(MorphImages)
+#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 ParseMagickOption  PrependMagickMethod(ParseMagickOption)
+#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 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 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 RegisterAVIImage  PrependMagickMethod(RegisterAVIImage)
+#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 RegisterDPSImage  PrependMagickMethod(RegisterDPSImage)
+#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 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 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 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 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 ResetStringInfo  PrependMagickMethod(ResetStringInfo)
+#define ResetTimer  PrependMagickMethod(ResetTimer)
+#define ResizeImage  PrependMagickMethod(ResizeImage)
+#define ResizeMagickMemory  PrependMagickMethod(ResizeMagickMemory)
+#define ResizeQuantumMemory  PrependMagickMethod(ResizeQuantumMemory)
+#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 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 StringToDouble  PrependMagickMethod(StringToDouble)
+#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 UniqueImageColors  PrependMagickMethod(UniqueImageColors)
+#define UnlockSemaphoreInfo  PrependMagickMethod(UnlockSemaphoreInfo)
+#define UnmapBlob  PrependMagickMethod(UnmapBlob)
+#define UnregisterARTImage  PrependMagickMethod(UnregisterARTImage)
+#define UnregisterAVIImage  PrependMagickMethod(UnregisterAVIImage)
+#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 UnregisterDPSImage  PrependMagickMethod(UnregisterDPSImage)
+#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 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 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 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 XGetPixelPacket  PrependMagickMethod(XGetPixelPacket)
+#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/magick/mime-private.h b/magick/mime-private.h
new file mode 100644
index 0000000..1ea2c47
--- /dev/null
+++ b/magick/mime-private.h
@@ -0,0 +1,38 @@
+/*
+  Copyright 1999-2009 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/magick/mime.c b/magick/mime.c
new file mode 100644
index 0000000..c00be35
--- /dev/null
+++ b/magick/mime.c
@@ -0,0 +1,1080 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                        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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/memory_.h"
+#include "magick/mime.h"
+#include "magick/mime-private.h"
+#include "magick/option.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MimeFilename  "mime.xml"
+
+/*
+  Typedef declaration.
+*/
+struct _MimeInfo
+{
+  char
+    *path,
+    *type,
+    *description,
+    *pattern;
+
+  long
+    priority;
+
+  MagickOffsetType
+    offset;
+
+  size_t
+    extent;
+
+  DataType
+    data_type;
+
+  long
+    mask,
+    value;
+
+  EndianType
+    endian;
+
+  size_t
+    length;
+
+  unsigned char
+    *magic;
+
+  MagickBooleanType
+    stealth;
+
+  unsigned long
+    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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M i m e L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMimeList() deallocates memory associated with the mime list.
+%
+%  The format of the DestroyMimeList method is:
+%
+%      DestroyMimeList(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 DestroyMimeList(void)
+{
+  AcquireSemaphoreInfo(&mime_semaphore);
+  if (mime_list != (LinkedListInfo *) NULL)
+    mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
+  instantiate_mime=MagickFalse;
+  RelinquishSemaphoreInfo(mime_semaphore);
+  DestroySemaphoreInfo(&mime_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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;
+
+  long
+    value;
+
+  register const MimeInfo
+    *p;
+
+  register const unsigned char
+    *q;
+
+  register long
+    i;
+
+  unsigned long
+    lsb_first;
+
+  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;
+  AcquireSemaphoreInfo(&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=(*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=(*q++);
+            value|=(*q++) << 8;
+          }
+        else
+          {
+            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 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=(*q++);
+            value|=(*q++) << 8;
+            value|=(*q++) << 16;
+            value|=(*q++) << 24;
+          }
+        else
+          {
+            value=(*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 <= (long) 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));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_aliases,ExceptionInfo *exception)
+{
+  const MimeInfo
+    **aliases;
+
+  register const MimeInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate mime list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(mime_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
+  aliases[i]=(MimeInfo *) NULL;
+  *number_aliases=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_aliases,ExceptionInfo *exception)
+{
+  char
+    **aliases;
+
+  register const MimeInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (unsigned long *) 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);
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(mime_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
+  aliases[i]=(char *) NULL;
+  *number_aliases=(unsigned long) 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))
+    {
+      AcquireSemaphoreInfo(&mime_semaphore);
+      if ((mime_list == (LinkedListInfo *) NULL) &&
+          (instantiate_mime == MagickFalse))
+        {
+          (void) LoadMimeLists(MimeFilename,exception);
+          instantiate_mime=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  unsigned long
+    number_aliases;
+
+  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 < (long) 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) fprintf(file,"\nPath: %s\n\n",mime_info[i]->path);
+        (void) fprintf(file,"Type                   Description\n");
+        (void) fprintf(file,"-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=mime_info[i]->path;
+    (void) fprintf(file,"%s",mime_info[i]->type);
+    if (strlen(mime_info[i]->type) <= 25)
+      {
+        for (j=(long) strlen(mime_info[i]->type); j <= 27; j++)
+          (void) fprintf(file," ");
+      }
+    else
+      {
+        (void) fprintf(file,"\n");
+        for (j=0; j <= 27; j++)
+          (void) fprintf(file," ");
+      }
+    if (mime_info[i]->description != (char *) NULL)
+      (void) fprintf(file,"%s",mime_info[i]->description);
+    (void) fprintf(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 unsigned long 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 unsigned long 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) ParseMagickOption(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) ParseMagickOption(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=strtol((char *) mime_info->magic,(char **) NULL,0);
+      }
+    attribute=GetXMLTreeAttribute(mime,"mask");
+    if (attribute != (const char *) NULL)
+      mime_info->mask=strtol(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=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) FormatMagickString(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) FormatMagickString(media,MaxTextExtent,"image/x-%s",magick);
+  LocaleLower(media+8);
+  return(ConstantString(media));
+}
diff --git a/magick/mime.h b/magick/mime.h
new file mode 100644
index 0000000..81ec707
--- /dev/null
+++ b/magick/mime.h
@@ -0,0 +1,51 @@
+/*
+  Copyright 1999-2009 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 *,unsigned long *,ExceptionInfo *),
+  *MagickToMime(const char *);
+
+extern MagickExport const char
+  *GetMimeDescription(const MimeInfo *),
+  *GetMimeType(const MimeInfo *);
+
+extern MagickExport MagickBooleanType
+  ListMimeInfo(FILE *,ExceptionInfo *),
+  LoadMimeLists(const char *,ExceptionInfo *);
+
+extern MagickExport const MimeInfo
+  *GetMimeInfo(const char *,const unsigned char *,const size_t,ExceptionInfo *),
+  **GetMimeInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyMimeList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/module.c b/magick/module.c
new file mode 100644
index 0000000..60687f2
--- /dev/null
+++ b/magick/module.c
@@ -0,0 +1,1541 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/coder.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/log.h"
+#include "magick/hashmap.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/module.h"
+#include "magick/policy.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/static.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/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 *),
+  InitializeModuleList(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.
+  */
+  AcquireSemaphoreInfo(&module_semaphore);
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  if (module_list != (SplayTreeInfo *) NULL)
+    module_list=DestroySplayTree(module_list);
+  if (instantiate_module != MagickFalse)
+    (void) lt_dlexit();
+#endif
+  instantiate_module=MagickFalse;
+  RelinquishSemaphoreInfo(module_semaphore);
+  DestroySemaphoreInfo(&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
+      AcquireSemaphoreInfo(&module_semaphore);
+      ResetSplayTreeIterator(module_list);
+      p=(ModuleInfo *) GetNextValueInSplayTree(module_list);
+      RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_modules,ExceptionInfo *exception)
+{
+  const ModuleInfo
+    **modules;
+
+  register const ModuleInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate module list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_modules != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(module_semaphore);
+  qsort((void *) modules,(size_t) i,sizeof(*modules),ModuleInfoCompare);
+  modules[i]=(ModuleInfo *) NULL;
+  *number_modules=(unsigned long) 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,unsigned long *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 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,
+  unsigned long *number_modules,ExceptionInfo *exception)
+{
+  char
+    **modules,
+    filename[MaxTextExtent],
+    module_path[MaxTextExtent],
+    path[MaxTextExtent];
+
+  DIR
+    *directory;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  struct dirent
+    *buffer,
+    *entry;
+
+  unsigned long
+    max_entries;
+
+  /*
+    Locate all modules in the coder path.
+  */
+  TagToCoderModuleName("magick",filename);
+  length=GetMagickModulePath(filename,MagickImageCoderModule,module_path,
+    exception);
+  if (length == 0)
+    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 >= (long) 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]);
+    LocaleUpper(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=(unsigned long) 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) FormatMagickString(path,MaxTextExtent,"%s%s",directory,filename);
+      if (IsPathAccessible(path) == MagickFalse)
+        {
+          ThrowFileException(exception,ConfigureWarning,
+            "UnableToOpenModuleFile",path);
+          return(MagickFalse);
+        }
+      return(MagickTrue);
+    }
+#else
+#if defined(__WINDOWS__)
+    {
+      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) FormatMagickString(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(__WINDOWS__)
+# error MAGICKCORE_CODER_PATH or __WINDOWS__ 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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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(__WINDOWS__)
+  {
+    /*
+      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) FormatMagickString(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));
+}
+
+static MagickBooleanType InitializeModuleList(
+  ExceptionInfo *magick_unused(exception))
+{
+  if ((module_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_module == MagickFalse))
+    {
+      AcquireSemaphoreInfo(&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;
+        }
+      RelinquishSemaphoreInfo(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;
+
+  ModuleHandle
+    handle;
+
+  PolicyRights
+    rights;
+
+  size_t
+    length;
+
+  /*
+    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)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",tag);
+      return(MagickFalse);
+    }
+  TagToFilterModuleName(tag,name);
+  length=GetMagickModulePath(name,MagickImageFilterModule,path,exception);
+  if (length == 0)
+    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) FormatMagickString(name,MaxTextExtent,"%sImage",tag);
+#else
+  (void) FormatMagickString(name,MaxTextExtent,"%s%sImage",
+    MAGICKCORE_NAMESPACE_PREFIX,tag);
+#endif
+  /*
+    Execute the module.
+  */
+  image_filter=(ImageFilterHandler *) lt_dlsym(handle,name);
+  if (image_filter == (ImageFilterHandler *) NULL)
+    (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+      "UnableToLoadModule","`%s': %s",name,lt_dlerror());
+  else
+    {
+      unsigned long
+        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,signature,
+            MagickImageFilterSignature);
+          return(MagickFalse);
+        }
+    }
+  /*
+    Close the module.
+  */
+  if (lt_dlclose(handle) != 0)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleWarning,
+        "UnableToCloseModule","`%s': %s",name,lt_dlerror());
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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)
+{
+  const ModuleInfo
+    **module_info;
+
+  register long
+    i;
+
+  unsigned long
+    number_modules;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  module_info=GetModuleInfoList("*",&number_modules,exception);
+  if (module_info == (const ModuleInfo **) NULL)
+    return(MagickFalse);
+  if (module_info[0]->path != (char *) NULL)
+    {
+      char
+        path[MaxTextExtent];
+
+      GetPathComponent(module_info[0]->path,HeadPath,path);
+      (void) fprintf(file,"\nPath: %s\n\n",path);
+    }
+  (void) fprintf(file,"Module\n");
+  (void) fprintf(file,"-------------------------------------------------"
+    "------------------------------\n");
+  for (i=0; i < (long) number_modules; i++)
+  {
+    if (module_info[i]->stealth != MagickFalse)
+      continue;
+    (void) fprintf(file,"%s",module_info[i]->tag);
+    (void) fprintf(file,"\n");
+  }
+  (void) fflush(file);
+  module_info=(const ModuleInfo **)
+    RelinquishMagickMemory((void *) module_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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];
+
+  ModuleHandle
+    handle;
+
+  ModuleInfo
+    *module_info;
+
+  register const CoderInfo
+    *p;
+
+  size_t
+    length;
+
+  unsigned long
+    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';
+  length=GetMagickModulePath(filename,MagickImageCoderModule,path,exception);
+  if (length == 0)
+    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=(unsigned long (*)(void)) lt_dlsym(handle,name);
+  if (module_info->register_module == (unsigned long (*)(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,
+        signature,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 long
+    i;
+
+  unsigned long
+    number_modules;
+
+  /*
+    Load all modules.
+  */
+  (void) GetMagickInfo((char *) NULL,exception);
+  number_modules=0;
+  modules=GetModuleList("*",&number_modules,exception);
+  if (modules == (char **) NULL)
+    return(MagickFalse);
+  for (i=0; i < (long) number_modules; i++)
+    (void) OpenModule(modules[i],exception);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; i < (long) 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) FormatMagickString(name,MaxTextExtent,"%s.la",tag);
+  (void) LocaleLower(name);
+#else
+#if defined(__WINDOWS__)
+  if (LocaleNCompare("IM_MOD_",tag,7) == 0)
+    (void) CopyMagickString(name,tag,MaxTextExtent);
+  else
+    {
+#if defined(_DEBUG)
+      (void) FormatMagickString(name,MaxTextExtent,"IM_MOD_DB_%s_.dll",tag);
+#else
+      (void) FormatMagickString(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) FormatMagickString(name,MaxTextExtent,"%s.dll",tag);
+#else
+  (void) FormatMagickString(name,MaxTextExtent,"%s.la",tag);
+  (void) LocaleLower(name);
+#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) FormatMagickString(module,MaxTextExtent,format,name);
+#else
+  {
+    char
+      prefix_format[MaxTextExtent];
+
+    (void) FormatMagickString(prefix_format,MaxTextExtent,"%s%s",
+      MAGICKCORE_NAMESPACE_PREFIX,format);
+    (void) FormatMagickString(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)
+{
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  {
+    extern unsigned long
+      analyzeImage(Image **,const int,const char **,ExceptionInfo *);
+
+    ImageFilterHandler
+      *image_filter;
+
+    image_filter=(ImageFilterHandler *) NULL;
+    if (LocaleCompare("analyze",tag) == 0)
+      image_filter=analyzeImage;
+    if (image_filter != (ImageFilterHandler *) NULL)
+      {
+        unsigned long
+          signature;
+
+        signature=image_filter(image,argc,argv,exception);
+        if (signature != MagickImageFilterSignature)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+              "ImageFilterSignatureMismatch","`%s': %8lx != %8lx",tag,signature,
+              MagickImageFilterSignature);
+            return(MagickFalse);
+          }
+      }
+  }
+#endif
+  return(MagickTrue);
+}
+#endif
diff --git a/magick/module.h b/magick/module.h
new file mode 100644
index 0000000..d968345
--- /dev/null
+++ b/magick/module.h
@@ -0,0 +1,94 @@
+/*
+  Copyright 1999-2009 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 "magick/version.h"
+
+#define MagickImageCoderSignature  ((unsigned long) \
+  (((MagickLibVersion) << 8) | MAGICKCORE_QUANTUM_DEPTH))
+#define MagickImageFilterSignature  ((unsigned long) \
+  (((MagickLibVersion) << 8) | MAGICKCORE_QUANTUM_DEPTH))
+
+typedef enum
+{
+  MagickImageCoderModule,
+  MagickImageFilterModule
+} MagickModuleType;
+
+typedef struct _ModuleInfo
+{
+  char
+    *path,
+    *tag;
+
+  void
+    *handle,
+    (*unregister_module)(void);
+
+  unsigned long
+    (*register_module)(void);
+
+  time_t
+    timestamp;
+
+  MagickBooleanType
+    stealth;
+
+  struct _ModuleInfo
+    *previous,
+    *next;  /* deprecated, use GetModuleInfoList() */
+
+  unsigned long
+    signature;
+} ModuleInfo;
+
+typedef ModuleExport unsigned long
+  ImageFilterHandler(Image **,const int,const char **,ExceptionInfo *);
+
+extern MagickExport char
+  **GetModuleList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const ModuleInfo
+  **GetModuleInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  InvokeDynamicImageFilter(const char *,Image **,const int,const char **,
+    ExceptionInfo *),
+  ListModuleInfo(FILE *,ExceptionInfo *),
+  OpenModule(const char *,ExceptionInfo *),
+  OpenModules(ExceptionInfo *);
+
+extern MagickExport ModuleInfo
+  *GetModuleInfo(const char *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyModuleList(void),
+  RegisterStaticModules(void),
+  UnregisterStaticModules(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/monitor-private.h b/magick/monitor-private.h
new file mode 100644
index 0000000..d6c17a5
--- /dev/null
+++ b/magick/monitor-private.h
@@ -0,0 +1,45 @@
+/*
+  Copyright 1999-2009 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 <magick/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);
+  if (QuantumTick(offset,extent) == MagickFalse)
+    return(MagickTrue);
+  (void) FormatMagickString(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/magick/monitor.c b/magick/monitor.c
new file mode 100644
index 0000000..092c919
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/image.h"
+#include "magick/log.h"
+#include "magick/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 span,
+%      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 span,
+%      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/magick/monitor.h b/magick/monitor.h
new file mode 100644
index 0000000..6b04d0f
--- /dev/null
+++ b/magick/monitor.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2009 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/magick/montage.c b/magick/montage.c
new file mode 100644
index 0000000..3a387d3
--- /dev/null
+++ b/magick/montage.c
@@ -0,0 +1,893 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/annotate.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/composite.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/quantize.h"
+#include "magick/property.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/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.opacity=OpaqueOpacity;
+  montage_info->stroke.opacity=(Quantum) TransparentOpacity;
+  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 unsigned long number_images,
+  long *x_offset,long *y_offset,unsigned long *tiles_per_column,
+  unsigned long *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=(unsigned long) sqrt((double) number_images);
+  if (*tiles_per_column == 0)
+    *tiles_per_column=(unsigned long)
+      ceil((double) number_images/(*tiles_per_row));
+  if (*tiles_per_row == 0)
+    *tiles_per_row=(unsigned long)
+      ceil((double) number_images/(*tiles_per_column));
+}
+
+static inline long MagickMax(const long x,const long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline long MagickMin(const long x,const long 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;
+
+  long
+    tile,
+    x,
+    x_offset,
+    y,
+    y_offset;
+
+  MagickBooleanType
+    concatenate,
+    proceed,
+    status;
+
+  MagickOffsetType
+    tiles;
+
+  MagickStatusType
+    flags;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  register long
+    i;
+
+  RectangleInfo
+    bounds,
+    geometry,
+    extract_info;
+
+  size_t
+    extent;
+
+  TypeMetric
+    metrics;
+
+  unsigned long
+    bevel_width,
+    border_width,
+    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;
+
+  /*
+    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 < (long) 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,i,number_images);
+    if (proceed == MagickFalse)
+      break;
+    image=DestroyImage(image);
+  }
+  if (i < (long) number_images)
+    {
+      if (thumbnail == (Image *) NULL)
+        i--;
+      for (tile=0; (long) 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 < (long) number_images; i++)
+    if (image_list[i]->scene == 0)
+      break;
+  if (i == (long) number_images)
+    qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
+      SceneCompare);
+  /*
+    Determine tiles per row and column.
+  */
+  tiles_per_column=(unsigned long) sqrt((double) number_images);
+  tiles_per_row=(unsigned long) 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=(long) montage_info->border_width;
+  extract_info.y=(long) 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) FormatMagickString(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=(long) frame_info.width/2;
+      if ((flags & PsiValue) == 0)
+        frame_info.inner_bevel=frame_info.outer_bevel;
+      frame_info.x=(long) frame_info.width;
+      frame_info.y=(long) frame_info.height;
+      bevel_width=(unsigned long) MagickMax(frame_info.inner_bevel,
+        frame_info.outer_bevel);
+      border_width=(unsigned long) MagickMax((long) frame_info.width,
+        (long) frame_info.height);
+    }
+  for (i=0; i < (long) 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=(unsigned long) (2*(metrics.ascent-metrics.descent)*
+      MultilineCensus(title)+2*extract_info.y);
+  number_lines=0;
+  for (i=0; i < (long) 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->scene=0;
+  images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
+  tiles=0;
+  total_tiles=(unsigned long) number_images;
+  for (i=0; i < (long) 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+=(long) title_offset;
+    max_height=0;
+    bounds.width=0;
+    bounds.height=0;
+    width=0;
+    for (tile=0; tile < (long) tiles_per_page; tile++)
+    {
+      if (tile < (long) 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+=width+(extract_info.x+border_width)*2;
+      if (x_offset > (long) bounds.width)
+        bounds.width=(unsigned long) x_offset;
+      if (((tile+1) == (long) 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+=(unsigned long) (height+(extract_info.y+border_width)*2+
+            (metrics.ascent-metrics.descent+4)*number_lines+
+            (montage_info->shadow != MagickFalse ? 4 : 0));
+          if (y_offset > (long) bounds.height)
+            bounds.height=(unsigned long) 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((long) tiles_per_page,(long) 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+=(long) title_offset;
+    (void) FormatMagickString(montage->montage,MaxTextExtent,"%ldx%ld%+ld%+ld",
+      (long) (extract_info.width+(extract_info.x+border_width)*2),
+      (long) (extract_info.height+(extract_info.y+border_width)*2+
+      (metrics.ascent-metrics.descent+4)*number_lines+
+      (montage_info->shadow != MagickFalse ? 4 : 0)),x_offset,y_offset);
+    *montage->directory='\0';
+    tile=0;
+    while (tile < MagickMin((long) tiles_per_page,(long) 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) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
+          montage->columns,(unsigned long) (metrics.ascent-metrics.descent),
+          0L,(long) 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+=(long) title_offset+extract_info.y;
+    max_height=0;
+    for (tile=0; tile < MagickMin((long) tiles_per_page,(long) 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) FormatMagickString(tile_geometry,MaxTextExtent,"%lux%lu+0+0",
+        image->columns,image->rows);
+      flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception);
+      x=(long) (geometry.x+border_width);
+      y=(long) (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+=(unsigned long) ((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("#000000",&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,OverCompositeOp,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) FormatMagickString(geometry,MaxTextExtent,
+                "%lux%lu%+ld%+ld",(montage_info->frame ? image->columns :
+                width)-2*border_width,(unsigned long) (metrics.ascent-
+                metrics.descent+4)*MultilineCensus(value),x_offset+
+                border_width,(montage_info->frame ? y_offset+height+
+                border_width+4 : y_offset+extract_info.height+border_width+
+                (montage_info->shadow != MagickFalse ? 4 : 0)));
+              (void) CloneString(&draw_info->geometry,geometry);
+              (void) CloneString(&draw_info->text,value);
+              (void) AnnotateImage(montage,draw_info);
+            }
+        }
+      x_offset+=width+(extract_info.x+border_width)*2;
+      if (((tile+1) == (long) tiles_per_page) ||
+          (((tile+1) % tiles_per_row) == 0))
+        {
+          x_offset=extract_info.x;
+          y_offset+=(unsigned long) (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) &&
+          (QuantumTick(tiles,total_tiles) != MagickFalse))
+        {
+          status=images->progress_monitor(MontageImageTag,tiles,total_tiles,
+            images->client_data);
+          if (status == MagickFalse)
+            break;
+        }
+      image_list[tile]=DestroyImage(image_list[tile]);
+      image=DestroyImage(image);
+      tiles++;
+    }
+    if ((i+1) < (long) 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);
+        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);
+  while (GetPreviousImageInList(montage) != (Image *) NULL)
+    montage=GetPreviousImageInList(montage);
+  return(montage);
+}
diff --git a/magick/montage.h b/magick/montage.h
new file mode 100644
index 0000000..61f5108
--- /dev/null
+++ b/magick/montage.h
@@ -0,0 +1,88 @@
+/*
+  Copyright 1999-2009 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;
+
+  unsigned long
+    border_width;
+
+  MagickBooleanType
+    shadow;
+
+  PixelPacket
+    fill,
+    stroke,
+    background_color,
+    border_color,
+    matte_color;
+
+  GravityType
+    gravity;
+
+  char
+    filename[MaxTextExtent];
+
+  MagickBooleanType
+    debug;
+
+  unsigned long
+    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/magick/nt-base.c b/magick/nt-base.c
new file mode 100644
index 0000000..c46b94a
--- /dev/null
+++ b/magick/nt-base.c
@@ -0,0 +1,2251 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                 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-2009 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 "magick/studio.h"
+#if defined(__WINDOWS__)
+#include "magick/client.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/resource_.h"
+#include "magick/timer.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/version.h"
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+#  include "ltdl.h"
+#endif
+#include "magick/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 GhostscriptVectors
+  gs_vectors;
+
+static void
+  *gs_dll_handle = (void *) NULL;
+
+/*
+  External declarations.
+*/
+#if !defined(__WINDOWS__)
+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) FormatMagickString(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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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)
+{
+  AsynchronousDestroyMagickResources();
+  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 error,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o error: 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 error,const char *reason,
+  const char *description)
+{
+  char
+    buffer[3*MaxTextExtent],
+    *message;
+
+  if (reason == (char *) NULL)
+    {
+      MagickCoreTerminus();
+      exit(0);
+    }
+  message=GetExceptionMessage(errno);
+  if ((description != (char *) NULL) && errno)
+    (void) FormatMagickString(buffer,MaxTextExtent,"%s: %s (%s) [%s].\n",
+      GetClientName(),reason,description,message);
+  else
+    if (description != (char *) NULL)
+      (void) FormatMagickString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+        GetClientName(),reason,description);
+    else
+      if (errno != 0)
+        (void) FormatMagickString(buffer,MaxTextExtent,"%s: %s [%s].\n",
+          GetClientName(),reason,message);
+      else
+        (void) FormatMagickString(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);
+#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;
+
+  long
+    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() obtains the path to the latest Ghostscript DLL.  The
+%  method returns MagickFalse if a value is not obtained.
+%
+%  The format of the NTGhostscriptDLL method is:
+%
+%      int NTGhostscriptDLL(char *path, int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: Pointer to buffer in which to return result.
+%
+%    o length: Length of buffer
+%
+*/
+
+#define GS_PRODUCT_AFPL "AFPL Ghostscript"
+#define GS_PRODUCT_ALADDIN "Aladdin Ghostscript"
+#define GS_PRODUCT_GNU "GNU Ghostscript"
+#define GS_PRODUCT_GPL "GPL Ghostscript"
+#define GS_MINIMUM_VERSION 550
+
+/*
+  Get Ghostscript versions for given product.
+  Store results starting at pver + 1 + offset.
+  Returns total number of versions in pver.
+*/
+static int NTGhostscriptProductVersions(int *pver,int offset,
+  const char *gs_productfamily)
+{
+  HKEY
+    hkey,
+    hkeyroot;
+
+  DWORD
+    cbData;
+
+  char
+    key[MaxTextExtent],
+    *p;
+
+  int
+    n = 0,
+    ver;
+
+  (void) FormatMagickString(key,MaxTextExtent,"Software\\%s",gs_productfamily);
+  hkeyroot = HKEY_LOCAL_MACHINE;
+  if (RegOpenKeyExA(hkeyroot,key,0,KEY_READ,&hkey) == ERROR_SUCCESS)
+    {
+      /*
+        Now enumerate the keys.
+      */
+      cbData = sizeof(key) / sizeof(char);
+      while (RegEnumKeyA(hkey,n,key,cbData) == ERROR_SUCCESS)
+      {
+        n++;
+        ver = 0;
+        p = key;
+        while (*p && (*p!='.')) {
+          ver = (ver * 10) + (*p - '0')*100;
+          p++;
+        }
+        if (*p == '.')
+          p++;
+        if (*p)
+          {
+            ver+=10*(*p-'0');
+            p++;
+          }
+        if (*p)
+          ver+=(*p - '0');
+        if ((n+offset) < pver[0])
+          pver[n+offset]=ver;
+      }
+      RegCloseKey(hkey);
+    }
+  return(n+offset);
+}
+
+/* Query registry to find which versions of Ghostscript are installed.
+ * Return version numbers in an integer array.
+ * On entry, the first element in the array must be the array size
+ * in elements.
+ * If all is well, TRUE is returned.
+ * On exit, the first element is set to the number of Ghostscript
+ * versions installed, and subsequent elements to the version
+ * numbers of Ghostscript.
+ * e.g. on entry {5, 0, 0, 0, 0}, on exit {3, 550, 600, 596, 0}
+ * Returned version numbers may not be sorted.
+ *
+ * If Ghostscript is not installed at all, return FALSE
+ * and set pver[0] to 0.
+ * If the array is not large enough, return FALSE
+ * and set pver[0] to the number of Ghostscript versions installed.
+ */
+
+static int NTGhostscriptEnumerateVersions(int *pver)
+{
+  int
+    n;
+
+  assert(pver != (int *) NULL);
+  n=NTGhostscriptProductVersions(pver,0,GS_PRODUCT_AFPL);
+  n=NTGhostscriptProductVersions(pver,n,GS_PRODUCT_ALADDIN);
+  n=NTGhostscriptProductVersions(pver,n,GS_PRODUCT_GNU);
+  n=NTGhostscriptProductVersions(pver,n,GS_PRODUCT_GPL);
+  if (n >= pver[0])
+    {
+      pver[0]=n;
+      return(FALSE);  /* too small */
+    }
+  if (n == 0)
+    {
+      pver[0] = 0;
+      return(FALSE);  /* not installed */
+    }
+  pver[0]=n;
+  return(TRUE);
+}
+
+/*
+ Get a named registry value.
+ Key = hkeyroot\\key, named value = name.
+ name, ptr, plen and return values are the same as in gp_getenv();
+*/
+static int NTGetRegistryValue(HKEY hkeyroot,const char *key,const char *name,
+  char *ptr,int *plen)
+{
+  HKEY
+    hkey;
+
+  DWORD
+    cbData,
+    keytype;
+
+  BYTE
+    b,
+    *bptr = (BYTE *)ptr;
+
+  LONG
+    rc;
+
+  if (RegOpenKeyExA(hkeyroot,key,0,KEY_READ,&hkey) == ERROR_SUCCESS)
+    {
+      keytype = REG_SZ;
+      cbData = *plen;
+      if (bptr == (BYTE *)NULL)
+        bptr=(&b);  /* Registry API won't return ERROR_MORE_DATA */
+      /* if ptr is NULL */
+      rc=RegQueryValueExA(hkey,(char *) name,0,&keytype,bptr,&cbData);
+      RegCloseKey(hkey);
+      if (rc == ERROR_SUCCESS)
+        {
+          *plen = cbData;
+          return 0;  /* found environment variable and copied it */
+        } else if (rc == ERROR_MORE_DATA) {
+        /* buffer wasn't large enough */
+          *plen = cbData;
+          return -1;
+        }
+    }
+  return(1);  /* not found */
+}
+
+static int NTGhostscriptGetProductString(int gs_revision,const char *name,
+  char *ptr,int len,const char *gs_productfamily)
+{
+  /* If using Win32, look in the registry for a value with
+   * the given name.  The registry value will be under the key
+   * HKEY_CURRENT_USER\Software\AFPL Ghostscript\N.NN
+   * or if that fails under the key
+   * HKEY_LOCAL_MACHINE\Software\AFPL Ghostscript\N.NN
+   * where "AFPL Ghostscript" is actually gs_productfamily
+   * and N.NN is obtained from gs_revision.
+   */
+
+  char
+    dotversion[MaxTextExtent],
+    key[MaxTextExtent];
+
+  int
+    code,
+    length;
+
+  DWORD version = GetVersion();
+
+  if (((HIWORD(version) & 0x8000) != 0) && ((HIWORD(version) & 0x4000) == 0))
+    {
+      /* Win32s */
+      return FALSE;
+    }
+  (void) FormatMagickString(dotversion,MaxTextExtent,"%d.%02d",(int)
+    (gs_revision/100),(int) (gs_revision % 100));
+  (void) FormatMagickString(key,MaxTextExtent,"Software\\%s\\%s",
+    gs_productfamily,dotversion);
+  length = len;
+  code = NTGetRegistryValue(HKEY_CURRENT_USER, key, name, ptr, &length);
+  if ( code == 0 )
+    return TRUE;  /* found it */
+  length = len;
+  code = NTGetRegistryValue(HKEY_LOCAL_MACHINE, key, name, ptr, &length);
+  if ( code == 0 )
+    return TRUE;  /* found it */
+  return FALSE;
+}
+
+static int NTGhostscriptGetString(int gs_revision,const char *name,char *ptr,
+  int len)
+{
+  if (NTGhostscriptGetProductString(gs_revision,name,ptr,len,GS_PRODUCT_AFPL))
+    return(TRUE);
+  if (NTGhostscriptGetProductString(gs_revision,name,ptr,len,GS_PRODUCT_ALADDIN))
+    return(TRUE);
+  if (NTGhostscriptGetProductString(gs_revision,name,ptr,len,GS_PRODUCT_GNU))
+    return(TRUE);
+  if (NTGhostscriptGetProductString(gs_revision,name,ptr,len,GS_PRODUCT_GPL))
+    return(TRUE);
+  return(FALSE);
+}
+
+static int NTGetLatestGhostscript( void )
+{
+  int
+    count,
+    i,
+    gsver,
+    *ver;
+
+  DWORD version = GetVersion();
+  if ( ((HIWORD(version) & 0x8000)!=0) && ((HIWORD(version) & 0x4000)==0) )
+    return FALSE;  /* win32s */
+
+  count = 1;
+  NTGhostscriptEnumerateVersions(&count);
+  if (count < 1)
+    return FALSE;
+  ver=(int *) AcquireQuantumMemory(count+1UL,sizeof(*ver));
+  if (ver == (int *)NULL)
+    return(FALSE);
+  ver[0]=count+1;
+  if (!NTGhostscriptEnumerateVersions(ver))
+    {
+      ver=(int *) RelinquishMagickMemory(ver);
+      return FALSE;
+    }
+  gsver = 0;
+  for (i=1; i<=ver[0]; i++) {
+    if (ver[i] > gsver)
+      gsver = ver[i];
+  }
+  ver=(int *) RelinquishMagickMemory(ver);
+  return(gsver);
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t D L L                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptDLL() obtains the path to the latest Ghostscript DLL.  The
+%  method returns MagickFalse if a value is not obtained.
+%
+%  The format of the NTGhostscriptDLL method is:
+%
+%      int NTGhostscriptDLL( char *path, int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: Pointer to path buffer to update
+%
+%    o length: Allocation size of path buffer.
+%
+*/
+MagickExport int NTGhostscriptDLL(char *path, int length)
+{
+  int
+    gsver;
+
+  char
+    buf[256];
+
+  *path='\0';
+  gsver = NTGetLatestGhostscript();
+  if ((gsver == FALSE) || (gsver < GS_MINIMUM_VERSION))
+    return FALSE;
+
+  if (!NTGhostscriptGetString(gsver, "GS_DLL", buf, sizeof(buf)))
+    return FALSE;
+
+  (void) CopyMagickString(path,buf,length+1);
+  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 GhostscriptVectors structure containing
+%  function vectors to invoke Ghostscript DLL functions. A null pointer is
+%  returned if there is an error with loading the DLL or retrieving the
+%  function vectors.
+%
+%  The format of the NTGhostscriptDLLVectors method is:
+%
+%      const GhostscriptVectors *NTGhostscriptDLLVectors(void)
+%
+*/
+MagickExport const GhostscriptVectors *NTGhostscriptDLLVectors( void )
+{
+  if (NTGhostscriptLoadDLL())
+    return(&gs_vectors);
+  return((GhostscriptVectors*) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 MagickFalse if a value is not obtained.
+%
+%  The format of the NTGhostscriptEXE method is:
+%
+%      int NTGhostscriptEXE(char *path, int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: Pointer to buffer in which to return result.
+%
+%    o length: Length of buffer
+%
+*/
+MagickExport int NTGhostscriptEXE(char *path,int length)
+{
+  int
+    gsver;
+
+  char
+    buf[256],
+    *p;
+
+  (void) CopyMagickString(path,"gswin32c.exe",length);
+  gsver=NTGetLatestGhostscript();
+  if ((gsver == FALSE) || (gsver < GS_MINIMUM_VERSION))
+    return(FALSE);
+  if (!NTGhostscriptGetString(gsver, "GS_DLL", buf, sizeof(buf)))
+    return(FALSE);
+  p=strrchr(buf, '\\');
+  if (p) {
+    p++;
+    *p = 0;
+    (void) CopyMagickString(p,"gswin32c.exe",sizeof(buf));
+    (void) CopyMagickString(path,buf,length+1);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t F o n t s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptFonts() gets the path to the Ghostscript fonts.  The method
+%  returns MagickFalse if an error occurs otherwise MagickTrue.
+%
+%  The format of the NTGhostscriptFonts method is:
+%
+%      int NTGhostscriptFonts(char *path,int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: Pointer to buffer in which to return result.
+%
+%    o length: Length of buffer.
+%
+*/
+MagickExport int NTGhostscriptFonts(char *path,int length)
+{
+  char
+    buffer[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  int
+    version;
+
+  register char
+    *p,
+    *q;
+
+  *path='\0';
+  version=NTGetLatestGhostscript();
+  if ((version == FALSE) || (version < GS_MINIMUM_VERSION))
+    return(FALSE);
+  if (!NTGhostscriptGetString(version,"GS_LIB",buffer,MaxTextExtent))
+    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';
+    FormatMagickString(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
+%  MagickTrue if it succeeds.
+%
+%  The format of the NTGhostscriptLoadDLL method is:
+%
+%      int NTGhostscriptLoadDLL(void)
+%
+*/
+MagickExport int NTGhostscriptLoadDLL(void)
+{
+  char
+    module_path[MaxTextExtent];
+
+  if (gs_dll_handle != (void *) NULL)
+    return(MagickTrue);
+  if (NTGhostscriptDLL(module_path,sizeof(module_path)) == MagickFalse)
+    return(MagickFalse);
+  gs_dll_handle=NTOpenLibrary(module_path);
+  if (gs_dll_handle == (void *) NULL)
+    return(MagickFalse);
+  (void) ResetMagickMemory((void *) &gs_vectors,0,sizeof(GhostscriptVectors));
+  gs_vectors.exit=(int (MagickDLLCall *)
+    (gs_main_instance *)) NTGetLibrarySymbol(gs_dll_handle,"gsapi_exit");
+  gs_vectors.init_with_args=(int (MagickDLLCall *)
+    (gs_main_instance *,int,char **))
+    (NTGetLibrarySymbol(gs_dll_handle,"gsapi_init_with_args"));
+  gs_vectors.new_instance=(int (MagickDLLCall *) (gs_main_instance **,void *))
+    (NTGetLibrarySymbol(gs_dll_handle,"gsapi_new_instance"));
+  gs_vectors.run_string=(int (MagickDLLCall *)
+    (gs_main_instance *,const char *,int,int *))
+    (NTGetLibrarySymbol(gs_dll_handle,"gsapi_run_string"));
+  gs_vectors.delete_instance=(void (MagickDLLCall *)(gs_main_instance *))
+    (NTGetLibrarySymbol(gs_dll_handle,"gsapi_delete_instance"));
+  if ((gs_vectors.exit == NULL) ||
+      (gs_vectors.init_with_args == NULL) ||
+      (gs_vectors.new_instance == NULL) ||
+      (gs_vectors.run_string == NULL) ||
+      (gs_vectors.delete_instance == NULL))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 if it is loaded.
+%
+%  The format of the NTGhostscriptUnLoadDLL method is:
+%
+%      int NTGhostscriptUnLoadDLL(void)
+%
+*/
+MagickExport int NTGhostscriptUnLoadDLL(void)
+{
+  if (gs_dll_handle == (void *) NULL)
+    return(MagickFalse);
+  NTCloseLibrary(gs_dll_handle);
+  gs_dll_handle=(void *) NULL;
+  (void) ResetMagickMemory((void *) &gs_vectors,0,sizeof(GhostscriptVectors));
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+
+  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)
+    return((DIR *) NULL);
+  length=ConcatenateMagickString(file_specification,DirectorySeparator,
+    MaxTextExtent);
+  if (length >= MaxTextExtent)
+    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)
+        {
+          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) FormatMagickString(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) FormatMagickString(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,long 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,long 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)
+{
+  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 NTSystemComman method is:
+%
+%      int NTSystemComman(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:
+%
+%      long NTSystemConfiguration(int name)
+%
+%  A description of each parameter follows:
+%
+%    o name: _SC_PAGE_SIZE or _SC_PHYS_PAGES.
+%
+*/
+MagickExport long 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((long) status.dwTotalPhys/system_info.dwPageSize);
+        }
+      status.dwLength=sizeof(status);
+      if (module(&status) == 0)
+        return(0L);
+      return((long) 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:
+%
+%      long NTTellDirectory(DIR *entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+*/
+MagickExport long 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)
+{
+  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 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 NTWarningHandler(const ExceptionType warning,
+  const char *reason,const char *description)
+{
+  char
+    buffer[2*MaxTextExtent];
+
+  if (reason == (char *) NULL)
+    return;
+  if (description == (char *) NULL)
+    (void) FormatMagickString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatMagickString(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/magick/nt-base.h b/magick/nt-base.h
new file mode 100644
index 0000000..25e4ef0
--- /dev/null
+++ b/magick/nt-base.h
@@ -0,0 +1,379 @@
+/*
+  Copyright 1999-2009 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 "magick/delegate.h"
+#include "magick/delegate-private.h"
+#include "magick/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(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)
+#  define fseeko  _fseeki64
+#endif
+#if !defined(fstat) && !defined(__BORLANDC__)
+#if defined(__WINDOWS__) && !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)
+#  define ftello  _ftelli64
+#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(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(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(stat) && !defined(__BORLANDC__)
+#if defined(__WINDOWS__) && !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(telldir)
+#  define telldir(directory)  NTTellDirectory(directory)
+#endif
+#if !defined(tempnam)
+#  define tempnam  _tempnam
+#endif
+#if !defined(vsnprintf)
+#if !defined(_MSC_VER) || (defined(_MSC_VER) && (_MSC_VER < 1500))
+#define vsnprintf _vsnprintf 
+#endif
+#endif
+#if !defined(write)
+#  define write  _write
+#endif
+#if !defined(wstat) && !defined(__BORLANDC__)
+#if defined(__WINDOWS__) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) &&  (__MSVCRT_VERSION__ < 0x800)
+#  define wstat  _wstati64
+#else
+#  define wstat  _wstat
+#endif
+#endif
+
+#if defined(_MT) && defined(__WINDOWS__)
+#  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;
+
+typedef UINT
+  (CALLBACK *LPFNDLLFUNC1)(DWORD,UINT);
+
+typedef UINT
+  (CALLBACK *LPFNDLLFUNC2)(NTMEMORYSTATUSEX *);
+
+#endif
+
+#if !defined(ssize_t) && !defined(__MINGW32__)
+typedef long ssize_t;
+#endif
+
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+#  if defined(_WIN32)
+#    define BZ_IMPORT 1
+#  endif
+#endif
+
+extern MagickExport char
+  *NTGetLastError(void);
+
+extern MagickExport const GhostscriptVectors
+  *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),
+  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 long
+  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 *,long),
+  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/magick/nt-feature.c b/magick/nt-feature.c
new file mode 100644
index 0000000..8fa1755
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#if defined(__WINDOWS__) || defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#include <windows.h>
+#include "magick/cache.h"
+#include "magick/colorspace.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/quantum.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/splay-tree.h"
+#include "magick/utility.h"
+#include "magick/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"
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  RectangleInfo
+    page;
+
+  register const PixelPacket
+    *p;
+
+  BITMAP
+    bitmap;
+
+  HBITMAP
+    bitmapH;
+
+  HANDLE
+    bitmap_bitsH;
+
+  register RGBQUAD
+    *q;
+
+  RGBQUAD
+    *bitmap_bits;
+
+  /*
+    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+(long) geometry->width) < 0) ||
+      ((geometry->y+(long) geometry->height) < 0) ||
+      (geometry->x >= (long) image->columns) ||
+      (geometry->y >= (long) image->rows))
+    ThrowImageException(OptionError,"GeometryDoesNotContainImage");
+  page=(*geometry);
+  if ((page.x+(long) page.width) > (long) image->columns)
+    page.width=image->columns-page.x;
+  if ((page.y+(long) page.height) > (long) 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        = page.width;
+  bitmap.bmHeight       = 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 < (long) page.height; y++)
+  {
+    p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception);
+    if (p == (const PixelPacket *) 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 */
+      {
+        long
+          x;
+
+        /* Transfer pixels, scaling to Quantum */
+        for( x=page.width ; x> 0 ; x-- )
+          {
+            q->rgbRed = ScaleQuantumToChar(p->red);
+            q->rgbGreen = ScaleQuantumToChar(p->green);
+            q->rgbBlue = ScaleQuantumToChar(p->blue);
+            q->rgbReserved = 0;
+            ++q;
+            ++p;
+          }
+      }
+#endif
+    proceed=SetImageProgress(image,CropImageTag,y,page.height);
+    if (proceed == MagickFalse)
+      break;
+  }
+  if (y < (long) 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;
+
+  long
+    y;
+
+  register long
+    x;
+
+  register const PixelPacket
+    *p;
+
+  register RGBQUAD
+    *q;
+
+  RGBQUAD
+    *bitmap_bits;
+
+  size_t
+    length;
+
+  (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap));
+  bitmap.bmType=0;
+  bitmap.bmWidth=image->columns;
+  bitmap.bmHeight=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 < (long) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      q->rgbRed=ScaleQuantumToChar(p->red);
+      q->rgbGreen=ScaleQuantumToChar(p->green);
+      q->rgbBlue=ScaleQuantumToChar(p->blue);
+      q->rgbReserved=0;
+      p++;
+      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/magick/nt-feature.h b/magick/nt-feature.h
new file mode 100644
index 0000000..b571659
--- /dev/null
+++ b/magick/nt-feature.h
@@ -0,0 +1,43 @@
+/*
+  Copyright 1999-2009 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 "magick/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/magick/option.c b/magick/option.c
new file mode 100644
index 0000000..899879c
--- /dev/null
+++ b/magick/option.c
@@ -0,0 +1,2262 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/compare.h"
+#include "magick/constitute.h"
+#include "magick/distort.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/layer.h"
+#include "magick/mime-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/policy.h"
+#include "magick/property.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/resource_.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+
+/*
+  ImageMagick options.
+*/
+static const OptionInfo
+  AlignOptions[] =
+  {
+    { "Undefined", (long) UndefinedAlign, MagickTrue },
+    { "Center", (long) CenterAlign, MagickFalse },
+    { "End", (long) RightAlign, MagickFalse },
+    { "Left", (long) LeftAlign, MagickFalse },
+    { "Middle", (long) CenterAlign, MagickFalse },
+    { "Right", (long) RightAlign, MagickFalse },
+    { "Start", (long) LeftAlign, MagickFalse },
+    { (char *) NULL, (long) UndefinedAlign, MagickFalse }
+  },
+  AlphaOptions[] =
+  {
+    { "Undefined", (long) UndefinedAlphaChannel, MagickTrue },
+    { "Activate", (long) ActivateAlphaChannel, MagickFalse },
+    { "Background", (long) BackgroundAlphaChannel, MagickFalse },
+    { "Copy", (long) CopyAlphaChannel, MagickFalse },
+    { "Deactivate", (long) DeactivateAlphaChannel, MagickFalse },
+    { "Extract", (long) ExtractAlphaChannel, MagickFalse },
+    { "Off", (long) DeactivateAlphaChannel, MagickFalse },
+    { "On", (long) ActivateAlphaChannel, MagickFalse },
+    { "Opaque", (long) OpaqueAlphaChannel, MagickFalse },
+    { "Set", (long) SetAlphaChannel, MagickFalse },
+    { "Shape", (long) ShapeAlphaChannel, MagickFalse },
+    { "Reset", (long) SetAlphaChannel, MagickTrue }, /* deprecated */
+    { "Transparent", (long) TransparentAlphaChannel, MagickFalse },
+    { (char *) NULL, (long) UndefinedAlphaChannel, MagickFalse }
+  },
+  BooleanOptions[] =
+  {
+    { "False", 0L, MagickFalse },
+    { "True", 1L, MagickFalse },
+    { "0", 0L, MagickFalse },
+    { "1", 1L, MagickFalse },
+    { (char *) NULL, 0L, MagickFalse }
+  },
+  ChannelOptions[] =
+  {
+    { "Undefined", (long) UndefinedChannel, MagickTrue },
+    { "All", (long) AllChannels, MagickFalse },
+    { "Alpha", (long) OpacityChannel, MagickFalse },
+    { "Black", (long) BlackChannel, MagickFalse },
+    { "Blue", (long) BlueChannel, MagickFalse },
+    { "Cyan", (long) CyanChannel, MagickFalse },
+    { "Default", (long) DefaultChannels, MagickFalse },
+    { "Gray", (long) GrayChannel, MagickFalse },
+    { "Green", (long) GreenChannel, MagickFalse },
+    { "Hue", (long) RedChannel, MagickFalse },
+    { "Index", (long) IndexChannel, MagickFalse },
+    { "Lightness", (long) BlueChannel, MagickFalse },
+    { "Luminance", (long) BlueChannel, MagickFalse },
+    { "Luminosity", (long) BlueChannel, MagickFalse },  /* deprecated */
+    { "Magenta", (long) MagentaChannel, MagickFalse },
+    { "Matte", (long) OpacityChannel, MagickFalse },
+    { "Opacity", (long) OpacityChannel, MagickFalse },
+    { "Red", (long) RedChannel, MagickFalse },
+    { "Saturation", (long) GreenChannel, MagickFalse },
+    { "Yellow", (long) YellowChannel, MagickFalse },
+    { "Sync", (long) SyncChannels, MagickFalse },   /* special channel flag */
+    { (char *) NULL, (long) UndefinedChannel, MagickFalse }
+  },
+  ClassOptions[] =
+  {
+    { "Undefined", (long) UndefinedClass, MagickTrue },
+    { "DirectClass", (long) DirectClass, MagickFalse },
+    { "PseudoClass", (long) PseudoClass, MagickFalse },
+    { (char *) NULL, (long) UndefinedClass, MagickFalse }
+  },
+  ClipPathOptions[] =
+  {
+    { "Undefined", (long) UndefinedPathUnits, MagickTrue },
+    { "ObjectBoundingBox", (long) ObjectBoundingBox, MagickFalse },
+    { "UserSpace", (long) UserSpace, MagickFalse },
+    { "UserSpaceOnUse", (long) UserSpaceOnUse, MagickFalse },
+    { (char *) NULL, (long) UndefinedPathUnits, MagickFalse }
+  },
+  CommandOptions[] =
+  {
+    { "+adjoin", 0L, MagickFalse },
+    { "-adjoin", 0L, MagickFalse },
+    { "+adaptive-sharpen", 1L, MagickFalse },
+    { "-adaptive-sharpen", 1L, MagickFalse },
+    { "+adaptive-threshold", 1L, MagickFalse },
+    { "-adaptive-threshold", 1L, MagickFalse },
+    { "+affine", 0L, MagickFalse },
+    { "-affine", 1L, MagickFalse },
+    { "+affinity", 0L, MagickFalse },
+    { "-affinity", 1L, MagickFalse },
+    { "+alpha", 1L, MagickFalse },
+    { "-alpha", 1L, MagickFalse },
+    { "+annotate", 0L, MagickFalse },
+    { "-annotate", 2L, MagickFalse },
+    { "+antialias", 0L, MagickFalse },
+    { "-antialias", 0L, MagickFalse },
+    { "+append", 0L, MagickFalse },
+    { "-append", 0L, MagickFalse },
+    { "+authenticate", 0L, MagickFalse },
+    { "-authenticate", 1L, MagickFalse },
+    { "+auto-gamma", 0L, MagickTrue },   /* under development */
+    { "-auto-gamma", 0L, MagickTrue },   /* under development */
+    { "+auto-level", 0L, MagickTrue },   /* under development */
+    { "-auto-level", 0L, MagickTrue },   /* under development */
+    { "+auto-orient", 0L, MagickFalse },
+    { "-auto-orient", 0L, MagickFalse },
+    { "+average", 0L, MagickFalse },
+    { "-average", 0L, MagickFalse },
+    { "+backdrop", 0L, MagickFalse },
+    { "-backdrop", 1L, MagickFalse },
+    { "+background", 0L, MagickFalse },
+    { "-background", 1L, MagickFalse },
+    { "+bench", 0L, MagickTrue },
+    { "-bench", 1L, MagickTrue },
+    { "+bias", 0L, MagickFalse },
+    { "-bias", 1L, MagickFalse },
+    { "+black-threshold", 0L, MagickFalse },
+    { "-black-threshold", 1L, MagickFalse },
+    { "+blend", 0L, MagickFalse },
+    { "-blend", 1L, MagickFalse },
+    { "+blue-primary", 0L, MagickFalse },
+    { "-blue-primary", 1L, MagickFalse },
+    { "+blue-shift", 1L, MagickFalse },
+    { "-blue-shift", 1L, MagickFalse },
+    { "+blur", 0L, MagickFalse },
+    { "-blur", 1L, MagickFalse },
+    { "+border", 0L, MagickFalse },
+    { "-border", 1L, MagickFalse },
+    { "+bordercolor", 0L, MagickFalse },
+    { "-bordercolor", 1L, MagickFalse },
+    { "+borderwidth", 0L, MagickFalse },
+    { "-borderwidth", 1L, MagickFalse },
+    { "+box", 0L, MagickFalse },
+    { "-box", 1L, MagickFalse },
+    { "+cache", 0L, MagickFalse },
+    { "-cache", 1L, MagickFalse },
+    { "+cdl", 1L, MagickFalse },
+    { "-cdl", 1L, MagickFalse },
+    { "+channel", 0L, MagickFalse },
+    { "-channel", 1L, MagickFalse },
+    { "+charcoal", 0L, MagickFalse },
+    { "-charcoal", 0L, MagickFalse },
+    { "+chop", 0L, MagickFalse },
+    { "-chop", 1L, MagickFalse },
+    { "+clip", 0L, MagickFalse },
+    { "-clip", 0L, MagickFalse },
+    { "+clip-mask", 0L, MagickFalse },
+    { "-clip-mask", 1L, MagickFalse },
+    { "+clip-path", 0L, MagickFalse },
+    { "-clip-path", 1L, MagickFalse },
+    { "+clone", 0L, MagickFalse },
+    { "-clone", 1L, MagickFalse },
+    { "+clut", 0L, MagickFalse },
+    { "-clut", 0L, MagickFalse },
+    { "+coalesce", 0L, MagickFalse },
+    { "-coalesce", 0L, MagickFalse },
+    { "+colorize", 0L, MagickFalse },
+    { "-colorize", 1L, MagickFalse },
+    { "+colormap", 0L, MagickFalse },
+    { "-colormap", 1L, MagickFalse },
+    { "+colors", 0L, MagickFalse },
+    { "-colors", 1L, MagickFalse },
+    { "+colorspace", 0L, MagickFalse },
+    { "-colorspace", 1L, MagickFalse },
+    { "+combine", 0L, MagickFalse },
+    { "-combine", 0L, MagickFalse },
+    { "+comment", 0L, MagickFalse },
+    { "-comment", 1L, MagickFalse },
+    { "+compose", 0L, MagickFalse },
+    { "-compose", 1L, MagickFalse },
+    { "+composite", 0L, MagickFalse },
+    { "-composite", 0L, MagickFalse },
+    { "+compress", 0L, MagickFalse },
+    { "-compress", 1L, MagickFalse },
+    { "+contrast", 0L, MagickFalse },
+    { "-contrast", 0L, MagickFalse },
+    { "+contrast-stretch", 0L, MagickFalse },
+    { "-contrast-stretch", 1L, MagickFalse },
+    { "+convolve", 0L, MagickFalse },
+    { "-convolve", 1L, MagickFalse },
+    { "+crop", 0L, MagickFalse },
+    { "-crop", 1L, MagickFalse },
+    { "+cycle", 0L, MagickFalse },
+    { "-cycle", 1L, MagickFalse },
+    { "+debug", 0L, MagickFalse },
+    { "-debug", 1L, MagickFalse },
+    { "+decipher", 1L, MagickFalse },
+    { "-decipher", 1L, MagickFalse },
+    { "+deconstruct", 0L, MagickFalse },
+    { "-deconstruct", 0L, MagickFalse },
+    { "+define", 1L, MagickFalse },
+    { "-define", 1L, MagickFalse },
+    { "+delay", 0L, MagickFalse },
+    { "-delay", 1L, MagickFalse },
+    { "+delete", 0L, MagickFalse },
+    { "-delete", 1L, MagickFalse },
+    { "+density", 0L, MagickFalse },
+    { "-density", 1L, MagickFalse },
+    { "+depth", 0L, MagickFalse },
+    { "-depth", 1L, MagickFalse },
+    { "+descend", 0L, MagickFalse },
+    { "-descend", 1L, MagickFalse },
+    { "+deskew", 0L, MagickFalse },
+    { "-deskew", 1L, MagickFalse },
+    { "+despeckle", 0L, MagickFalse },
+    { "-despeckle", 0L, MagickFalse },
+    { "+displace", 0L, MagickFalse },
+    { "-displace", 1L, MagickFalse },
+    { "+display", 0L, MagickFalse },
+    { "-display", 1L, MagickFalse },
+    { "+dispose", 0L, MagickFalse },
+    { "-dispose", 1L, MagickFalse },
+    { "+dissolve", 0L, MagickFalse },
+    { "-dissolve", 1L, MagickFalse },
+    { "+distort", 2L, MagickFalse },
+    { "-distort", 2L, MagickFalse },
+    { "+dither", 0L, MagickFalse },
+    { "-dither", 1L, MagickFalse },
+    { "+draw", 0L, MagickFalse },
+    { "-draw", 1L, MagickFalse },
+    { "+edge", 0L, MagickFalse },
+    { "-edge", 1L, MagickFalse },
+    { "+emboss", 0L, MagickFalse },
+    { "-emboss", 1L, MagickFalse },
+    { "+encipher", 1L, MagickFalse },
+    { "-encipher", 1L, MagickFalse },
+    { "+encoding", 0L, MagickFalse },
+    { "-encoding", 1L, MagickFalse },
+    { "+endian", 0L, MagickFalse },
+    { "-endian", 1L, MagickFalse },
+    { "+enhance", 0L, MagickFalse },
+    { "-enhance", 0L, MagickFalse },
+    { "+equalize", 0L, MagickFalse },
+    { "-equalize", 0L, MagickFalse },
+    { "+evaluate", 0L, MagickFalse },
+    { "-evaluate", 2L, MagickFalse },
+    { "+extent", 0L, MagickFalse },
+    { "-extent", 1L, MagickFalse },
+    { "+extract", 0L, MagickFalse },
+    { "-extract", 1L, MagickFalse },
+    { "+family", 0L, MagickFalse },
+    { "-family", 1L, MagickFalse },
+    { "+fill", 0L, MagickFalse },
+    { "-fill", 1L, MagickFalse },
+    { "+filter", 0L, MagickFalse },
+    { "-filter", 1L, MagickFalse },
+    { "+flatten", 0L, MagickFalse },
+    { "-flatten", 0L, MagickFalse },
+    { "+flip", 0L, MagickFalse },
+    { "-flip", 0L, MagickFalse },
+    { "+floodfill", 0L, MagickFalse },
+    { "-floodfill", 2L, MagickFalse },
+    { "+flop", 0L, MagickFalse },
+    { "-flop", 0L, MagickFalse },
+    { "+font", 0L, MagickFalse },
+    { "-font", 1L, MagickFalse },
+    { "+foreground", 0L, MagickFalse },
+    { "-foreground", 1L, MagickFalse },
+    { "+format", 0L, MagickFalse },
+    { "-format", 1L, MagickFalse },
+    { "+frame", 0L, MagickFalse },
+    { "-frame", 1L, MagickFalse },
+    { "+fuzz", 0L, MagickFalse },
+    { "-fuzz", 1L, MagickFalse },
+    { "+fx", 0L, MagickFalse },
+    { "-fx", 1L, MagickFalse },
+    { "+gamma", 0L, MagickFalse },
+    { "-gamma", 1L, MagickFalse },
+    { "+gaussian", 0L, MagickFalse },
+    { "-gaussian", 1L, MagickFalse },
+    { "+gaussian-blur", 0L, MagickFalse },
+    { "-gaussian-blur", 1L, MagickFalse },
+    { "+geometry", 0L, MagickFalse },
+    { "-geometry", 1L, MagickFalse },
+    { "+gravity", 0L, MagickFalse },
+    { "-gravity", 1L, MagickFalse },
+    { "+green-primary", 0L, MagickFalse },
+    { "-green-primary", 1L, MagickFalse },
+    { "+hald-clut", 0L, MagickFalse },
+    { "-hald-clut", 0L, MagickFalse },
+    { "+help", 0L, MagickFalse },
+    { "-help", 0L, MagickFalse },
+    { "+highlight-color", 1L, MagickFalse },
+    { "-highlight-color", 1L, MagickFalse },
+    { "+iconGeometry", 0L, MagickFalse },
+    { "-iconGeometry", 1L, MagickFalse },
+    { "+iconic", 0L, MagickFalse },
+    { "-iconic", 1L, MagickFalse },
+    { "+identify", 0L, MagickFalse },
+    { "-identify", 0L, MagickFalse },
+    { "+immutable", 0L, MagickFalse },
+    { "-immutable", 0L, MagickFalse },
+    { "+implode", 0L, MagickFalse },
+    { "-implode", 1L, MagickFalse },
+    { "+insert", 0L, MagickFalse },
+    { "-insert", 1L, MagickFalse },
+    { "+intent", 0L, MagickFalse },
+    { "-intent", 1L, MagickFalse },
+    { "+interlace", 0L, MagickFalse },
+    { "-interlace", 1L, MagickFalse },
+    { "+interpolate", 0L, MagickFalse },
+    { "-interpolate", 1L, MagickFalse },
+    { "+interword-spacing", 0L, MagickFalse },
+    { "-interword-spacing", 1L, MagickFalse },
+    { "+kerning", 0L, MagickFalse },
+    { "-kerning", 1L, MagickFalse },
+    { "+label", 0L, MagickFalse },
+    { "-label", 1L, MagickFalse },
+    { "+lat", 0L, MagickFalse },
+    { "-lat", 1L, MagickFalse },
+    { "+layers", 0L, MagickFalse },
+    { "-layers", 1L, MagickFalse },
+    { "+level", 1L, MagickFalse },
+    { "-level", 1L, MagickFalse },
+    { "+level-colors", 1L, MagickFalse },
+    { "-level-colors", 1L, MagickFalse },
+    { "+limit", 0L, MagickFalse },
+    { "-limit", 2L, MagickFalse },
+    { "+linear-stretch", 0L, MagickFalse },
+    { "-linear-stretch", 1L, MagickFalse },
+    { "+linewidth", 0L, MagickFalse },
+    { "-linewidth", 1L, MagickFalse },
+    { "+liquid-rescale", 0L, MagickFalse },
+    { "-liquid-rescale", 1L, MagickFalse },
+    { "+list", 0L, MagickFalse },
+    { "-list", 1L, MagickFalse },
+    { "+log", 0L, MagickFalse },
+    { "-log", 1L, MagickFalse },
+    { "+loop", 0L, MagickFalse },
+    { "-loop", 1L, MagickFalse },
+    { "+lowlight-color", 1L, MagickFalse },
+    { "-lowlight-color", 1L, MagickFalse },
+    { "+magnify", 0L, MagickFalse },
+    { "-magnify", 1L, MagickFalse },
+    { "+map", 0L, MagickFalse },
+    { "-map", 1L, MagickFalse },
+    { "+mask", 0L, MagickFalse },
+    { "-mask", 1L, MagickFalse },
+    { "+matte", 0L, MagickFalse },
+    { "-matte", 0L, MagickFalse },
+    { "+mattecolor", 0L, MagickFalse },
+    { "-mattecolor", 1L, MagickFalse },
+    { "+median", 0L, MagickFalse },
+    { "-median", 1L, MagickFalse },
+    { "+metric", 0L, MagickFalse },
+    { "-metric", 1L, MagickFalse },
+    { "+mode", 0L, MagickFalse },
+    { "-mode", 1L, MagickFalse },
+    { "+modulate", 0L, MagickFalse },
+    { "-modulate", 1L, MagickFalse },
+    { "+monitor", 0L, MagickFalse },
+    { "-monitor", 0L, MagickFalse },
+    { "+monochrome", 0L, MagickFalse },
+    { "-monochrome", 0L, MagickFalse },
+    { "+morph", 0L, MagickFalse },
+    { "-morph", 1L, MagickFalse },
+    { "+mosaic", 0L, MagickFalse },
+    { "-mosaic", 0L, MagickFalse },
+    { "+motion-blur", 0L, MagickFalse },
+    { "-motion-blur", 1L, MagickFalse },
+    { "+name", 0L, MagickFalse },
+    { "-name", 1L, MagickFalse },
+    { "+negate", 0L, MagickFalse },
+    { "-negate", 0L, MagickFalse },
+    { "+noise", 1L, MagickFalse },
+    { "-noise", 1L, MagickFalse },
+    { "+noop", 0L, MagickFalse },
+    { "-noop", 0L, MagickFalse },
+    { "+normalize", 0L, MagickFalse },
+    { "-normalize", 0L, MagickFalse },
+    { "+opaque", 1L, MagickFalse },
+    { "-opaque", 1L, MagickFalse },
+    { "+ordered-dither", 0L, MagickFalse },
+    { "-ordered-dither", 1L, MagickFalse },
+    { "+orient", 0L, MagickFalse },
+    { "-orient", 1L, MagickFalse },
+    { "+origin", 0L, MagickFalse },
+    { "-origin", 1L, MagickFalse },
+    { "+page", 0L, MagickFalse },
+    { "-page", 1L, MagickFalse },
+    { "+paint", 0L, MagickFalse },
+    { "-paint", 1L, MagickFalse },
+    { "+path", 0L, MagickFalse },
+    { "-path", 1L, MagickFalse },
+    { "+pause", 0L, MagickFalse },
+    { "-pause", 1L, MagickFalse },
+    { "+passphrase", 0L, MagickFalse },
+    { "-passphrase", 1L, MagickFalse },
+    { "+pen", 0L, MagickFalse },
+    { "-pen", 1L, MagickFalse },
+    { "+ping", 0L, MagickFalse },
+    { "-ping", 0L, MagickFalse },
+    { "+pointsize", 0L, MagickFalse },
+    { "-pointsize", 1L, MagickFalse },
+    { "+polaroid", 0L, MagickFalse },
+    { "-polaroid", 1L, MagickFalse },
+    { "+posterize", 0L, MagickFalse },
+    { "-posterize", 1L, MagickFalse },
+    { "+preview", 0L, MagickFalse },
+    { "-preview", 1L, MagickFalse },
+    { "+process", 0L, MagickFalse },
+    { "-process", 1L, MagickFalse },
+    { "+profile", 1L, MagickFalse },
+    { "-profile", 1L, MagickFalse },
+    { "+quality", 0L, MagickFalse },
+    { "-quality", 1L, MagickFalse },
+    { "+quiet", 0L, MagickFalse },
+    { "-quiet", 0L, MagickFalse },
+    { "+radial-blur", 0L, MagickFalse },
+    { "-radial-blur", 1L, MagickFalse },
+    { "+raise", 0L, MagickFalse },
+    { "-raise", 1L, MagickFalse },
+    { "+random-threshold", 0L, MagickFalse },
+    { "-random-threshold", 1L, MagickFalse },
+    { "+recolor", 0L, MagickFalse },
+    { "-recolor", 1L, MagickFalse },
+    { "+red-primary", 0L, MagickFalse },
+    { "-red-primary", 1L, MagickFalse },
+    { "+regard-warnings", 0L, MagickFalse },
+    { "-regard-warnings", 0L, MagickFalse },
+    { "+region", 0L, MagickFalse },
+    { "-region", 1L, MagickFalse },
+    { "+remote", 0L, MagickFalse },
+    { "-remote", 1L, MagickFalse },
+    { "+render", 0L, MagickFalse },
+    { "-render", 0L, MagickFalse },
+    { "+repage", 0L, MagickFalse },
+    { "-repage", 1L, MagickFalse },
+    { "+resample", 0L, MagickFalse },
+    { "-resample", 1L, MagickFalse },
+    { "+resize", 0L, MagickFalse },
+    { "-resize", 1L, MagickFalse },
+    { "+respect-parenthesis", 0L, MagickFalse },
+    { "-respect-parenthesis", 0L, MagickFalse },
+    { "+reverse", 0L, MagickFalse },
+    { "-reverse", 0L, MagickFalse },
+    { "+roll", 0L, MagickFalse },
+    { "-roll", 1L, MagickFalse },
+    { "+rotate", 0L, MagickFalse },
+    { "-rotate", 1L, MagickFalse },
+    { "+sample", 0L, MagickFalse },
+    { "-sample", 1L, MagickFalse },
+    { "+sampling-factor", 0L, MagickFalse },
+    { "-sampling-factor", 1L, MagickFalse },
+    { "+sans", 0L, MagickFalse },
+    { "-sans", 1L, MagickFalse },
+    { "+sans0", 0L, MagickFalse },
+    { "-sans0", 0L, MagickFalse },
+    { "+sans2", 2L, MagickFalse },
+    { "-sans2", 2L, MagickFalse },
+    { "+scale", 0L, MagickFalse },
+    { "-scale", 1L, MagickFalse },
+    { "+scene", 0L, MagickFalse },
+    { "-scene", 1L, MagickFalse },
+    { "+scenes", 0L, MagickFalse },
+    { "-scenes", 1L, MagickFalse },
+    { "+screen", 0L, MagickFalse },
+    { "-screen", 1L, MagickFalse },
+    { "+seed", 0L, MagickFalse },
+    { "-seed", 1L, MagickFalse },
+    { "+segment", 0L, MagickFalse },
+    { "-segment", 1L, MagickFalse },
+    { "+separate", 0L, MagickFalse },
+    { "-separate", 0L, MagickFalse },
+    { "+sepia-tone", 0L, MagickFalse },
+    { "-sepia-tone", 1L, MagickFalse },
+    { "+set", 1L, MagickFalse },
+    { "-set", 2L, MagickFalse },
+    { "+shade", 0L, MagickFalse },
+    { "-shade", 1L, MagickFalse },
+    { "+shadow", 0L, MagickFalse },
+    { "-shadow", 1L, MagickFalse },
+    { "+shared-memory", 0L, MagickFalse },
+    { "-shared-memory", 1L, MagickFalse },
+    { "+sharpen", 0L, MagickFalse },
+    { "-sharpen", 1L, MagickFalse },
+    { "+shave", 0L, MagickFalse },
+    { "-shave", 1L, MagickFalse },
+    { "+shear", 0L, MagickFalse },
+    { "-shear", 1L, MagickFalse },
+    { "+sigmoidal-contrast", 0L, MagickFalse },
+    { "-sigmoidal-contrast", 1L, MagickFalse },
+    { "+silent", 0L, MagickFalse },
+    { "-silent", 1L, MagickFalse },
+    { "+size", 0L, MagickFalse },
+    { "-size", 1L, MagickFalse },
+    { "+sketch", 0L, MagickFalse },
+    { "-sketch", 1L, MagickFalse },
+    { "+snaps", 0L, MagickFalse },
+    { "-snaps", 1L, MagickFalse },
+    { "+solarize", 0L, MagickFalse },
+    { "-solarize", 1L, MagickFalse },
+    { "+splice", 0L, MagickFalse },
+    { "-splice", 1L, MagickFalse },
+    { "+sparse-color", 2L, MagickFalse },
+    { "-sparse-color", 2L, MagickFalse },
+    { "+spread", 0L, MagickFalse },
+    { "-spread", 1L, MagickFalse },
+    { "+stegano", 0L, MagickFalse },
+    { "-stegano", 1L, MagickFalse },
+    { "+stereo", 0L, MagickFalse },
+    { "-stereo", 1L, MagickFalse },
+    { "+stretch", 0L, MagickFalse },
+    { "-stretch", 1L, MagickFalse },
+    { "+strip", 0L, MagickFalse },
+    { "-strip", 0L, MagickFalse },
+    { "+stroke", 0L, MagickFalse },
+    { "-stroke", 1L, MagickFalse },
+    { "+strokewidth", 0L, MagickFalse },
+    { "-strokewidth", 1L, MagickFalse },
+    { "+style", 0L, MagickFalse },
+    { "-style", 1L, MagickFalse },
+    { "+swap", 0L, MagickFalse },
+    { "-swap", 1L, MagickFalse },
+    { "+swirl", 0L, MagickFalse },
+    { "-swirl", 1L, MagickFalse },
+    { "+text-font", 0L, MagickFalse },
+    { "-text-font", 1L, MagickFalse },
+    { "+texture", 0L, MagickFalse },
+    { "-texture", 1L, MagickFalse },
+    { "+threshold", 0L, MagickFalse },
+    { "-threshold", 1L, MagickFalse },
+    { "+thumbnail", 0L, MagickFalse },
+    { "-thumbnail", 1L, MagickFalse },
+    { "+thumnail", 0L, MagickFalse },
+    { "-thumnail", 1L, MagickFalse },
+    { "+tile", 0L, MagickFalse },
+    { "-tile", 1L, MagickFalse },
+    { "+tile-offset", 0L, MagickFalse },
+    { "-tile-offset", 1L, MagickFalse },
+    { "+tint", 0L, MagickFalse },
+    { "-tint", 1L, MagickFalse },
+    { "+title", 0L, MagickFalse },
+    { "-title", 1L, MagickFalse },
+    { "+transform", 0L, MagickFalse },
+    { "-transform", 0L, MagickFalse },
+    { "+transparent", 1L, MagickFalse },
+    { "-transparent", 1L, MagickFalse },
+    { "+transparent-color", 1L, MagickFalse },
+    { "-transparent-color", 1L, MagickFalse },
+    { "+transpose", 0L, MagickFalse },
+    { "-transpose", 0L, MagickFalse },
+    { "+transverse", 0L, MagickFalse },
+    { "-transverse", 0L, MagickFalse },
+    { "+treedepth", 0L, MagickFalse },
+    { "-treedepth", 1L, MagickFalse },
+    { "+trim", 0L, MagickFalse },
+    { "-trim", 0L, MagickFalse },
+    { "+type", 0L, MagickFalse },
+    { "-type", 1L, MagickFalse },
+    { "+undercolor", 0L, MagickFalse },
+    { "-undercolor", 1L, MagickFalse },
+    { "+unique-colors", 0L, MagickFalse },
+    { "-unique-colors", 0L, MagickFalse },
+    { "+units", 0L, MagickFalse },
+    { "-units", 1L, MagickFalse },
+    { "+unsharp", 0L, MagickFalse },
+    { "-unsharp", 1L, MagickFalse },
+    { "+update", 0L, MagickFalse },
+    { "-update", 1L, MagickFalse },
+    { "+use-pixmap", 0L, MagickFalse },
+    { "-use-pixmap", 1L, MagickFalse },
+    { "+verbose", 0L, MagickFalse },
+    { "-verbose", 0L, MagickFalse },
+    { "+version", 0L, MagickFalse },
+    { "-version", 1L, MagickFalse },
+    { "+view", 0L, MagickFalse },
+    { "-view", 1L, MagickFalse },
+    { "+vignette", 0L, MagickFalse },
+    { "-vignette", 1L, MagickFalse },
+    { "+virtual-pixel", 0L, MagickFalse },
+    { "-virtual-pixel", 1L, MagickFalse },
+    { "+visual", 0L, MagickFalse },
+    { "-visual", 1L, MagickFalse },
+    { "+watermark", 0L, MagickFalse },
+    { "-watermark", 1L, MagickFalse },
+    { "+wave", 0L, MagickFalse },
+    { "-wave", 1L, MagickFalse },
+    { "+weight", 0L, MagickFalse },
+    { "-weight", 1L, MagickFalse },
+    { "+white-point", 0L, MagickFalse },
+    { "-white-point", 1L, MagickFalse },
+    { "+white-threshold", 0L, MagickFalse },
+    { "-white-threshold", 1L, MagickFalse },
+    { "+window", 0L, MagickFalse },
+    { "-window", 1L, MagickFalse },
+    { "+window-group", 0L, MagickFalse },
+    { "-window-group", 1L, MagickFalse },
+    { "+write", 0L, MagickFalse },
+    { "-write", 1L, MagickFalse },
+    { (char *) NULL, (long) 0L, MagickFalse }
+  },
+  ComposeOptions[] =
+  {
+    { "Undefined", (long) UndefinedCompositeOp, MagickTrue },
+    { "Add", (long) AddCompositeOp, MagickFalse },
+    { "Atop", (long) AtopCompositeOp, MagickFalse },
+    { "Blend", (long) BlendCompositeOp, MagickFalse },
+    { "Blur", (long) BlurCompositeOp, MagickFalse },
+    { "Bumpmap", (long) BumpmapCompositeOp, MagickFalse },
+    { "ChangeMask", (long) ChangeMaskCompositeOp, MagickFalse },
+    { "Clear", (long) ClearCompositeOp, MagickFalse },
+    { "ColorBurn", (long) ColorBurnCompositeOp, MagickFalse },
+    { "ColorDodge", (long) ColorDodgeCompositeOp, MagickFalse },
+    { "Colorize", (long) ColorizeCompositeOp, MagickFalse },
+    { "CopyBlack", (long) CopyBlackCompositeOp, MagickFalse },
+    { "CopyBlue", (long) CopyBlueCompositeOp, MagickFalse },
+    { "CopyCyan", (long) CopyCyanCompositeOp, MagickFalse },
+    { "CopyGreen", (long) CopyGreenCompositeOp, MagickFalse },
+    { "Copy", (long) CopyCompositeOp, MagickFalse },
+    { "CopyMagenta", (long) CopyMagentaCompositeOp, MagickFalse },
+    { "CopyOpacity", (long) CopyOpacityCompositeOp, MagickFalse },
+    { "CopyRed", (long) CopyRedCompositeOp, MagickFalse },
+    { "CopyYellow", (long) CopyYellowCompositeOp, MagickFalse },
+    { "Darken", (long) DarkenCompositeOp, MagickFalse },
+    { "Divide", (long) DivideCompositeOp, MagickFalse },
+    { "Dst", (long) DstCompositeOp, MagickFalse },
+    { "Difference", (long) DifferenceCompositeOp, MagickFalse },
+    { "Displace", (long) DisplaceCompositeOp, MagickFalse },
+    { "Dissolve", (long) DissolveCompositeOp, MagickFalse },
+    { "Distort", (long) DistortCompositeOp, MagickFalse },
+    { "DstAtop", (long) DstAtopCompositeOp, MagickFalse },
+    { "DstIn", (long) DstInCompositeOp, MagickFalse },
+    { "DstOut", (long) DstOutCompositeOp, MagickFalse },
+    { "DstOver", (long) DstOverCompositeOp, MagickFalse },
+    { "Dst", (long) DstCompositeOp, MagickFalse },
+    { "Exclusion", (long) ExclusionCompositeOp, MagickFalse },
+    { "HardLight", (long) HardLightCompositeOp, MagickFalse },
+    { "Hue", (long) HueCompositeOp, MagickFalse },
+    { "In", (long) InCompositeOp, MagickFalse },
+    { "Lighten", (long) LightenCompositeOp, MagickFalse },
+    { "LinearBurn", (long) LinearBurnCompositeOp, MagickFalse },
+    { "LinearDodge", (long) LinearDodgeCompositeOp, MagickFalse },
+    { "LinearLight", (long) LinearLightCompositeOp, MagickFalse },
+    { "Luminize", (long) LuminizeCompositeOp, MagickFalse },
+    { "Mathematics", (long) MathematicsCompositeOp, MagickFalse },
+    { "Minus", (long) MinusCompositeOp, MagickFalse },
+    { "Modulate", (long) ModulateCompositeOp, MagickFalse },
+    { "Multiply", (long) MultiplyCompositeOp, MagickFalse },
+    { "None", (long) NoCompositeOp, MagickFalse },
+    { "Out", (long) OutCompositeOp, MagickFalse },
+    { "Overlay", (long) OverlayCompositeOp, MagickFalse },
+    { "Over", (long) OverCompositeOp, MagickFalse },
+    { "PegtopLight", (long) PegtopLightCompositeOp, MagickFalse },
+    { "PinLight", (long) PinLightCompositeOp, MagickFalse },
+    { "Plus", (long) PlusCompositeOp, MagickFalse },
+    { "Replace", (long) ReplaceCompositeOp, MagickFalse },
+    { "Saturate", (long) SaturateCompositeOp, MagickFalse },
+    { "Screen", (long) ScreenCompositeOp, MagickFalse },
+    { "SoftLight", (long) SoftLightCompositeOp, MagickFalse },
+    { "Src", (long) SrcCompositeOp, MagickFalse },
+    { "SrcAtop", (long) SrcAtopCompositeOp, MagickFalse },
+    { "SrcIn", (long) SrcInCompositeOp, MagickFalse },
+    { "SrcOut", (long) SrcOutCompositeOp, MagickFalse },
+    { "SrcOver", (long) SrcOverCompositeOp, MagickFalse },
+    { "Src", (long) SrcCompositeOp, MagickFalse },
+    { "Subtract", (long) SubtractCompositeOp, MagickFalse },
+    { "Threshold", (long) ThresholdCompositeOp, MagickTrue }, /* depreciate */
+    { "VividLight", (long) VividLightCompositeOp, MagickFalse },
+    { "Xor", (long) XorCompositeOp, MagickFalse },
+    { (char *) NULL, (long) UndefinedCompositeOp, MagickFalse }
+  },
+  CompressOptions[] =
+  {
+    { "Undefined", (long) UndefinedCompression, MagickTrue },
+    { "B44", (long) B44Compression, MagickFalse },
+    { "B44A", (long) B44ACompression, MagickFalse },
+    { "BZip", (long) BZipCompression, MagickFalse },
+    { "DXT1", (long) DXT1Compression, MagickFalse },
+    { "DXT3", (long) DXT3Compression, MagickFalse },
+    { "DXT5", (long) DXT5Compression, MagickFalse },
+    { "Fax", (long) FaxCompression, MagickFalse },
+    { "Group4", (long) Group4Compression, MagickFalse },
+    { "JPEG", (long) JPEGCompression, MagickFalse },
+    { "JPEG2000", (long) JPEG2000Compression, MagickFalse },
+    { "Lossless", (long) LosslessJPEGCompression, MagickFalse },
+    { "LosslessJPEG", (long) LosslessJPEGCompression, MagickFalse },
+    { "LZW", (long) LZWCompression, MagickFalse },
+    { "None", (long) NoCompression, MagickFalse },
+    { "Piz", (long) PizCompression, MagickFalse },
+    { "Pxr24", (long) Pxr24Compression, MagickFalse },
+    { "RLE", (long) RLECompression, MagickFalse },
+    { "Zip", (long) ZipCompression, MagickFalse },
+    { "RunlengthEncoded", (long) RLECompression, MagickFalse },
+    { "ZipS", (long) ZipSCompression, MagickFalse },
+    { (char *) NULL, (long) UndefinedCompression, MagickFalse }
+  },
+  ColorspaceOptions[] =
+  {
+    { "Undefined", (long) UndefinedColorspace, MagickTrue },
+    { "CMY", (long) CMYColorspace, MagickFalse },
+    { "CMYK", (long) CMYKColorspace, MagickFalse },
+    { "Gray", (long) GRAYColorspace, MagickFalse },
+    { "HSB", (long) HSBColorspace, MagickFalse },
+    { "HSL", (long) HSLColorspace, MagickFalse },
+    { "HWB", (long) HWBColorspace, MagickFalse },
+    { "Lab", (long) LabColorspace, MagickFalse },
+    { "Log", (long) LogColorspace, MagickFalse },
+    { "OHTA", (long) OHTAColorspace, MagickFalse },
+    { "Rec601Luma", (long) Rec601LumaColorspace, MagickFalse },
+    { "Rec601YCbCr", (long) Rec601YCbCrColorspace, MagickFalse },
+    { "Rec709Luma", (long) Rec709LumaColorspace, MagickFalse },
+    { "Rec709YCbCr", (long) Rec709YCbCrColorspace, MagickFalse },
+    { "RGB", (long) RGBColorspace, MagickFalse },
+    { "sRGB", (long) sRGBColorspace, MagickFalse },
+    { "Transparent", (long) TransparentColorspace, MagickFalse },
+    { "XYZ", (long) XYZColorspace, MagickFalse },
+    { "YCbCr", (long) YCbCrColorspace, MagickFalse },
+    { "YCC", (long) YCCColorspace, MagickFalse },
+    { "YIQ", (long) YIQColorspace, MagickFalse },
+    { "YPbPr", (long) YPbPrColorspace, MagickFalse },
+    { "YUV", (long) YUVColorspace, MagickFalse },
+    { (char *) NULL, (long) UndefinedColorspace, MagickFalse }
+  },
+  DataTypeOptions[] =
+  {
+    { "Undefined", (long) UndefinedData, MagickTrue },
+    { "Byte", (long) ByteData, MagickFalse },
+    { "Long", (long) LongData, MagickFalse },
+    { "Short", (long) ShortData, MagickFalse },
+    { "String", (long) StringData, MagickFalse },
+    { (char *) NULL, (long) UndefinedData, MagickFalse }
+  },
+  DecorateOptions[] =
+  {
+    { "Undefined", (long) UndefinedDecoration, MagickTrue },
+    { "LineThrough", (long) LineThroughDecoration, MagickFalse },
+    { "None", (long) NoDecoration, MagickFalse },
+    { "Overline", (long) OverlineDecoration, MagickFalse },
+    { "Underline", (long) UnderlineDecoration, MagickFalse },
+    { (char *) NULL, (long) UndefinedDecoration, MagickFalse }
+  },
+  DisposeOptions[] =
+  {
+    { "Background", (long) BackgroundDispose, MagickFalse },
+    { "None", (long) NoneDispose, MagickFalse },
+    { "Previous", (long) PreviousDispose, MagickFalse },
+    { "Undefined", (long) UndefinedDispose, MagickFalse },
+    { "0", (long) UndefinedDispose, MagickFalse },
+    { "1", (long) NoneDispose, MagickFalse },
+    { "2", (long) BackgroundDispose, MagickFalse },
+    { "3", (long) PreviousDispose, MagickFalse },
+    { (char *) NULL, (long) UndefinedDispose, MagickFalse }
+  },
+  DistortOptions[] =
+  {
+    { "Undefined", (long) UndefinedDistortion, MagickTrue },
+    { "Affine", (long) AffineDistortion, MagickFalse },
+    { "AffineProjection", (long) AffineProjectionDistortion, MagickFalse },
+    { "ScaleRotateTranslate", (long) ScaleRotateTranslateDistortion, MagickFalse },
+    { "SRT", (long) ScaleRotateTranslateDistortion, MagickFalse },
+    { "Perspective", (long) PerspectiveDistortion, MagickFalse },
+    { "PerspectiveProjection", (long) PerspectiveProjectionDistortion, MagickFalse },
+    { "Bilinear", (long) BilinearForwardDistortion, MagickTrue },
+    { "BilinearForward", (long) BilinearForwardDistortion, MagickFalse },
+    { "BilinearReverse", (long) BilinearReverseDistortion, MagickFalse },
+    { "Polynomial", (long) PolynomialDistortion, MagickFalse },
+    { "Arc", (long) ArcDistortion, MagickFalse },
+    { "Polar", (long) PolarDistortion, MagickFalse },
+    { "DePolar", (long) DePolarDistortion, MagickFalse },
+    { "Barrel", (long) BarrelDistortion, MagickFalse },
+    { "BarrelInverse", (long) BarrelInverseDistortion, MagickFalse },
+    { "Shepards", (long) ShepardsDistortion, MagickFalse },
+    { (char *) NULL, (long) UndefinedDistortion, MagickFalse }
+  },
+  DitherOptions[] =
+  {
+    { "Undefined", (long) UndefinedDitherMethod, MagickTrue },
+    { "None", (long) NoDitherMethod, MagickFalse },
+    { "FloydSteinberg", (long) FloydSteinbergDitherMethod, MagickFalse },
+    { "Riemersma", (long) RiemersmaDitherMethod, MagickFalse },
+    { (char *) NULL, (long) UndefinedEndian, MagickFalse }
+  },
+  EndianOptions[] =
+  {
+    { "Undefined", (long) UndefinedEndian, MagickTrue },
+    { "LSB", (long) LSBEndian, MagickFalse },
+    { "MSB", (long) MSBEndian, MagickFalse },
+    { (char *) NULL, (long) UndefinedEndian, MagickFalse }
+  },
+  EvaluateOptions[] =
+  {
+    { "Undefined", (long) UndefinedEvaluateOperator, MagickTrue },
+    { "Add", (long) AddEvaluateOperator, MagickFalse },
+    { "AddModulus", (long) AddModulusEvaluateOperator, MagickFalse },
+    { "And", (long) AndEvaluateOperator, MagickFalse },
+    { "Cos", (long) CosineEvaluateOperator, MagickFalse },
+    { "Cosine", (long) CosineEvaluateOperator, MagickFalse },
+    { "Divide", (long) DivideEvaluateOperator, MagickFalse },
+    { "GaussianNoise", (long) GaussianNoiseEvaluateOperator, MagickFalse },
+    { "ImpulseNoise", (long) ImpulseNoiseEvaluateOperator, MagickFalse },
+    { "LaplacianNoise", (long) LaplacianNoiseEvaluateOperator, MagickFalse },
+    { "LeftShift", (long) LeftShiftEvaluateOperator, MagickFalse },
+    { "Log", (long) LogEvaluateOperator, MagickFalse },
+    { "Max", (long) MaxEvaluateOperator, MagickFalse },
+    { "Min", (long) MinEvaluateOperator, MagickFalse },
+    { "MultiplicativeNoise", (long) MultiplicativeNoiseEvaluateOperator, MagickFalse },
+    { "Multiply", (long) MultiplyEvaluateOperator, MagickFalse },
+    { "Or", (long) OrEvaluateOperator, MagickFalse },
+    { "PoissonNoise", (long) PoissonNoiseEvaluateOperator, MagickFalse },
+    { "Pow", (long) PowEvaluateOperator, MagickFalse },
+    { "RightShift", (long) RightShiftEvaluateOperator, MagickFalse },
+    { "Set", (long) SetEvaluateOperator, MagickFalse },
+    { "Sin", (long) SineEvaluateOperator, MagickFalse },
+    { "Sine", (long) SineEvaluateOperator, MagickFalse },
+    { "Subtract", (long) SubtractEvaluateOperator, MagickFalse },
+    { "Threshold", (long) ThresholdEvaluateOperator, MagickFalse },
+    { "ThresholdBlack", (long) ThresholdBlackEvaluateOperator, MagickFalse },
+    { "ThresholdWhite", (long) ThresholdWhiteEvaluateOperator, MagickFalse },
+    { "UniformNoise", (long) UniformNoiseEvaluateOperator, MagickFalse },
+    { "Xor", (long) XorEvaluateOperator, MagickFalse },
+    { (char *) NULL, (long) UndefinedEvaluateOperator, MagickFalse }
+  },
+  FillRuleOptions[] =
+  {
+    { "Undefined", (long) UndefinedRule, MagickTrue },
+    { "Evenodd", (long) EvenOddRule, MagickFalse },
+    { "NonZero", (long) NonZeroRule, MagickFalse },
+    { (char *) NULL, (long) UndefinedRule, MagickFalse }
+  },
+  FilterOptions[] =
+  {
+    { "Undefined", (long) UndefinedFilter, MagickTrue },
+    { "Bartlett", (long) BartlettFilter, MagickFalse },
+    { "Bessel", (long) BesselFilter, MagickFalse },
+    { "Blackman", (long) BlackmanFilter, MagickFalse },
+    { "Bohman", (long) BohmanFilter, MagickFalse },
+    { "Box", (long) BoxFilter, MagickFalse },
+    { "Catrom", (long) CatromFilter, MagickFalse },
+    { "Cubic", (long) CubicFilter, MagickFalse },
+    { "Gaussian", (long) GaussianFilter, MagickFalse },
+    { "Hamming", (long) HammingFilter, MagickFalse },
+    { "Hanning", (long) HanningFilter, MagickFalse },
+    { "Hermite", (long) HermiteFilter, MagickFalse },
+    { "Kaiser", (long) KaiserFilter, MagickFalse },
+    { "Lagrange", (long) LagrangeFilter, MagickFalse },
+    { "Lanczos", (long) LanczosFilter, MagickFalse },
+    { "Mitchell", (long) MitchellFilter, MagickFalse },
+    { "Parzen", (long) ParzenFilter, MagickFalse },
+    { "Point", (long) PointFilter, MagickFalse },
+    { "Quadratic", (long) QuadraticFilter, MagickFalse },
+    { "Sinc", (long) SincFilter, MagickFalse },
+    { "Triangle", (long) TriangleFilter, MagickFalse },
+    { "Welsh", (long) WelshFilter, MagickFalse },
+    { (char *) NULL, (long) UndefinedFilter, MagickFalse }
+  },
+  FunctionOptions[] =
+  {
+    { "Undefined", (long) UndefinedFunction, MagickTrue },
+    { "Polynomial", (long) PolynomialFunction, MagickFalse },
+    { "Sinusoid", (long) SinusoidFunction, MagickFalse },
+    { "ArcSin", (long) ArcsinFunction, MagickFalse },
+    { "ArcTan", (long) ArctanFunction, MagickFalse },
+    { (char *) NULL, (long) UndefinedFunction, MagickFalse }
+  },
+  GravityOptions[] =
+  {
+    { "Undefined", (long) UndefinedGravity, MagickTrue },
+    { "None", (long) UndefinedGravity, MagickFalse },
+    { "Center", (long) CenterGravity, MagickFalse },
+    { "East", (long) EastGravity, MagickFalse },
+    { "Forget", (long) ForgetGravity, MagickFalse },
+    { "NorthEast", (long) NorthEastGravity, MagickFalse },
+    { "North", (long) NorthGravity, MagickFalse },
+    { "NorthWest", (long) NorthWestGravity, MagickFalse },
+    { "SouthEast", (long) SouthEastGravity, MagickFalse },
+    { "South", (long) SouthGravity, MagickFalse },
+    { "SouthWest", (long) SouthWestGravity, MagickFalse },
+    { "West", (long) WestGravity, MagickFalse },
+    { "Static", (long) StaticGravity, MagickFalse },
+    { (char *) NULL, UndefinedGravity, MagickFalse }
+  },
+  ImageListOptions[] =
+  {
+    { "append", MagickTrue, MagickFalse },
+    { "affinity", MagickTrue, MagickFalse },
+    { "average", MagickTrue, MagickFalse },
+    { "clut", MagickTrue, MagickFalse },
+    { "coalesce", MagickTrue, MagickFalse },
+    { "combine", MagickTrue, MagickFalse },
+    { "composite", MagickTrue, MagickFalse },
+    { "crop", MagickTrue, MagickFalse },
+    { "debug", MagickTrue, MagickFalse },
+    { "deconstruct", MagickTrue, MagickFalse },
+    { "delete", MagickTrue, MagickFalse },
+    { "flatten", MagickTrue, MagickFalse },
+    { "fx", MagickTrue, MagickFalse },
+    { "hald-clut", MagickTrue, MagickFalse },
+    { "ift", MagickTrue, MagickFalse },
+    { "identify", MagickTrue, MagickFalse },
+    { "insert", MagickTrue, MagickFalse },
+    { "layers", MagickTrue, MagickFalse },
+    { "limit", MagickTrue, MagickFalse },
+    { "map", MagickTrue, MagickFalse },
+    { "morph", MagickTrue, MagickFalse },
+    { "mosaic", MagickTrue, MagickFalse },
+    { "optimize", MagickTrue, MagickFalse },
+    { "process", MagickTrue, MagickFalse },
+    { "quiet", MagickTrue, MagickFalse },
+    { "separate", MagickTrue, MagickFalse },
+    { "swap", MagickTrue, MagickFalse },
+    { "write", MagickTrue, MagickFalse },
+    { (char *) NULL, MagickFalse, MagickFalse }
+  },
+  IntentOptions[] =
+  {
+    { "Undefined", (long) UndefinedIntent, MagickTrue },
+    { "Absolute", (long) AbsoluteIntent, MagickFalse },
+    { "Perceptual", (long) PerceptualIntent, MagickFalse },
+    { "Relative", (long) RelativeIntent, MagickFalse },
+    { "Saturation", (long) SaturationIntent, MagickFalse },
+    { (char *) NULL, (long) UndefinedIntent, MagickFalse }
+  },
+  InterlaceOptions[] =
+  {
+    { "Undefined", (long) UndefinedInterlace, MagickTrue },
+    { "Line", (long) LineInterlace, MagickFalse },
+    { "None", (long) NoInterlace, MagickFalse },
+    { "Plane", (long) PlaneInterlace, MagickFalse },
+    { "Partition", (long) PartitionInterlace, MagickFalse },
+    { "GIF", (long) GIFInterlace, MagickFalse },
+    { "JPEG", (long) JPEGInterlace, MagickFalse },
+    { "PNG", (long) PNGInterlace, MagickFalse },
+    { (char *) NULL, (long) UndefinedInterlace, MagickFalse }
+  },
+  InterpolateOptions[] =
+  {
+    { "Undefined", (long) UndefinedInterpolatePixel, MagickTrue },
+    { "Average", (long) AverageInterpolatePixel, MagickFalse },
+    { "Bicubic", (long) BicubicInterpolatePixel, MagickFalse },
+    { "Bilinear", (long) BilinearInterpolatePixel, MagickFalse },
+    { "filter", (long) FilterInterpolatePixel, MagickFalse },
+    { "Integer", (long) IntegerInterpolatePixel, MagickFalse },
+    { "Mesh", (long) MeshInterpolatePixel, MagickFalse },
+    { "NearestNeighbor", (long) NearestNeighborInterpolatePixel, MagickFalse },
+    { "Spline", (long) SplineInterpolatePixel, MagickFalse },
+    { (char *) NULL, (long) UndefinedInterpolatePixel, MagickFalse }
+  },
+  LayerOptions[] =
+  {
+    { "Undefined", (long) UndefinedLayer, MagickTrue },
+    { "Coalesce", (long) CoalesceLayer, MagickFalse },
+    { "CompareAny", (long) CompareAnyLayer, MagickFalse },
+    { "CompareClear", (long) CompareClearLayer, MagickFalse },
+    { "CompareOverlay", (long) CompareOverlayLayer, MagickFalse },
+    { "Dispose", (long) DisposeLayer, MagickFalse },
+    { "Optimize", (long) OptimizeLayer, MagickFalse },
+    { "OptimizeFrame", (long) OptimizeImageLayer, MagickFalse },
+    { "OptimizePlus", (long) OptimizePlusLayer, MagickFalse },
+    { "OptimizeTransparency", (long) OptimizeTransLayer, MagickFalse },
+    { "RemoveDups", (long) RemoveDupsLayer, MagickFalse },
+    { "RemoveZero", (long) RemoveZeroLayer, MagickFalse },
+    { "Composite", (long) CompositeLayer, MagickFalse },
+    { "Merge", (long) MergeLayer, MagickFalse },
+    { "Flatten", (long) FlattenLayer, MagickFalse },
+    { "Mosaic", (long) MosaicLayer, MagickFalse },
+    { "TrimBounds", (long) TrimBoundsLayer, MagickFalse },
+    { (char *) NULL, (long) UndefinedLayer, MagickFalse }
+  },
+  LineCapOptions[] =
+  {
+    { "Undefined", (long) UndefinedCap, MagickTrue },
+    { "Butt", (long) ButtCap, MagickFalse },
+    { "Round", (long) RoundCap, MagickFalse },
+    { "Square", (long) SquareCap, MagickFalse },
+    { (char *) NULL, (long) UndefinedCap, MagickFalse }
+  },
+  LineJoinOptions[] =
+  {
+    { "Undefined", (long) UndefinedJoin, MagickTrue },
+    { "Bevel", (long) BevelJoin, MagickFalse },
+    { "Miter", (long) MiterJoin, MagickFalse },
+    { "Round", (long) RoundJoin, MagickFalse },
+    { (char *) NULL, (long) UndefinedJoin, MagickFalse }
+  },
+  ListOptions[] =
+  {
+    { "Align", (long) MagickAlignOptions, MagickFalse },
+    { "Alpha", (long) MagickAlphaOptions, MagickFalse },
+    { "Boolean", (long) MagickBooleanOptions, MagickFalse },
+    { "Channel", (long) MagickChannelOptions, MagickFalse },
+    { "Class", (long) MagickClassOptions, MagickFalse },
+    { "ClipPath", (long) MagickClipPathOptions, MagickFalse },
+    { "Coder", (long) MagickCoderOptions, MagickFalse },
+    { "Color", (long) MagickColorOptions, MagickFalse },
+    { "Colorspace", (long) MagickColorspaceOptions, MagickFalse },
+    { "Command", (long) MagickCommandOptions, MagickFalse },
+    { "Compose", (long) MagickComposeOptions, MagickFalse },
+    { "Compress", (long) MagickCompressOptions, MagickFalse },
+    { "Configure", (long) MagickConfigureOptions, MagickFalse },
+    { "DataType", (long) MagickDataTypeOptions, MagickFalse },
+    { "Debug", (long) MagickDebugOptions, MagickFalse },
+    { "Decoration", (long) MagickDecorateOptions, MagickFalse },
+    { "Delegate", (long) MagickDelegateOptions, MagickFalse },
+    { "Dispose", (long) MagickDisposeOptions, MagickFalse },
+    { "Distort", (long) MagickDistortOptions, MagickFalse },
+    { "Dither", (long) MagickDitherOptions, MagickFalse },
+    { "Endian", (long) MagickEndianOptions, MagickFalse },
+    { "Evaluate", (long) MagickEvaluateOptions, MagickFalse },
+    { "FillRule", (long) MagickFillRuleOptions, MagickFalse },
+    { "Filter", (long) MagickFilterOptions, MagickFalse },
+    { "Font", (long) MagickFontOptions, MagickFalse },
+    { "Format", (long) MagickFormatOptions, MagickFalse },
+    { "Function", (long) MagickFunctionOptions, MagickFalse },
+    { "Gravity", (long) MagickGravityOptions, MagickFalse },
+    { "ImageList", (long) MagickImageListOptions, MagickFalse },
+    { "Intent", (long) MagickIntentOptions, MagickFalse },
+    { "Interlace", (long) MagickInterlaceOptions, MagickFalse },
+    { "Interpolate", (long) MagickInterpolateOptions, MagickFalse },
+    { "Layers", (long) MagickLayerOptions, MagickFalse },
+    { "LineCap", (long) MagickLineCapOptions, MagickFalse },
+    { "LineJoin", (long) MagickLineJoinOptions, MagickFalse },
+    { "List", (long) MagickListOptions, MagickFalse },
+    { "Locale", (long) MagickLocaleOptions, MagickFalse },
+    { "LogEvent", (long) MagickLogEventOptions, MagickFalse },
+    { "Log", (long) MagickLogOptions, MagickFalse },
+    { "Magic", (long) MagickMagicOptions, MagickFalse },
+    { "Method", (long) MagickMethodOptions, MagickFalse },
+    { "Metric", (long) MagickMetricOptions, MagickFalse },
+    { "Mime", (long) MagickMimeOptions, MagickFalse },
+    { "Mode", (long) MagickModeOptions, MagickFalse },
+    { "Module", (long) MagickModuleOptions, MagickFalse },
+    { "Noise", (long) MagickNoiseOptions, MagickFalse },
+    { "Orientation", (long) MagickOrientationOptions, MagickFalse },
+    { "Policy", (long) MagickPolicyOptions, MagickFalse },
+    { "PolicyDomain", (long) MagickPolicyDomainOptions, MagickFalse },
+    { "PolicyRights", (long) MagickPolicyRightsOptions, MagickFalse },
+    { "Preview", (long) MagickPreviewOptions, MagickFalse },
+    { "Primitive", (long) MagickPrimitiveOptions, MagickFalse },
+    { "QuantumFormat", (long) MagickQuantumFormatOptions, MagickFalse },
+    { "Resource", (long) MagickResourceOptions, MagickFalse },
+    { "SparseColor", (long) MagickSparseColorOptions, MagickFalse },
+    { "Storage", (long) MagickStorageOptions, MagickFalse },
+    { "Stretch", (long) MagickStretchOptions, MagickFalse },
+    { "Style", (long) MagickStyleOptions, MagickFalse },
+    { "Threshold", (long) MagickThresholdOptions, MagickFalse },
+    { "Type", (long) MagickTypeOptions, MagickFalse },
+    { "Units", (long) MagickResolutionOptions, MagickFalse },
+    { "Undefined", (long) MagickUndefinedOptions, MagickTrue },
+    { "Validate", (long) MagickValidateOptions, MagickFalse },
+    { "VirtualPixel", (long) MagickVirtualPixelOptions, MagickFalse },
+    { (char *) NULL, (long) MagickUndefinedOptions, MagickFalse }
+  },
+  LogEventOptions[] =
+  {
+    { "Undefined", (long) UndefinedEvents, MagickTrue },
+    { "All", (long) (AllEvents &~ TraceEvent), MagickFalse },
+    { "Annotate", (long) AnnotateEvent, MagickFalse },
+    { "Blob", (long) BlobEvent, MagickFalse },
+    { "Cache", (long) CacheEvent, MagickFalse },
+    { "Coder", (long) CoderEvent, MagickFalse },
+    { "Configure", (long) ConfigureEvent, MagickFalse },
+    { "Deprecate", (long) DeprecateEvent, MagickFalse },
+    { "Draw", (long) DrawEvent, MagickFalse },
+    { "Exception", (long) ExceptionEvent, MagickFalse },
+    { "Locale", (long) LocaleEvent, MagickFalse },
+    { "Module", (long) ModuleEvent, MagickFalse },
+    { "None", (long) NoEvents, MagickFalse },
+    { "Policy", (long) PolicyEvent, MagickFalse },
+    { "Resource", (long) ResourceEvent, MagickFalse },
+    { "Trace", (long) TraceEvent, MagickFalse },
+    { "Transform", (long) TransformEvent, MagickFalse },
+    { "User", (long) UserEvent, MagickFalse },
+    { "Wand", (long) WandEvent, MagickFalse },
+    { "X11", (long) X11Event, MagickFalse },
+    { (char *) NULL, (long) UndefinedEvents, MagickFalse }
+  },
+  MetricOptions[] =
+  {
+    { "Undefined", (long) UndefinedMetric, MagickTrue },
+    { "AE", (long) AbsoluteErrorMetric, MagickFalse },
+    { "MAE", (long) MeanAbsoluteErrorMetric, MagickFalse },
+    { "MEPP", (long) MeanErrorPerPixelMetric, MagickFalse },
+    { "MSE", (long) MeanSquaredErrorMetric, MagickFalse },
+    { "PAE", (long) PeakAbsoluteErrorMetric, MagickFalse },
+    { "PSNR", (long) PeakSignalToNoiseRatioMetric, MagickFalse },
+    { "RMSE", (long) RootMeanSquaredErrorMetric, MagickFalse },
+    { (char *) NULL, (long) UndefinedMetric, MagickFalse }
+  },
+  MethodOptions[] =
+  {
+    { "Undefined", (long) UndefinedMethod, MagickTrue },
+    { "FillToBorder", (long) FillToBorderMethod, MagickFalse },
+    { "Floodfill", (long) FloodfillMethod, MagickFalse },
+    { "Point", (long) PointMethod, MagickFalse },
+    { "Replace", (long) ReplaceMethod, MagickFalse },
+    { "Reset", (long) ResetMethod, MagickFalse },
+    { (char *) NULL, (long) UndefinedMethod, MagickFalse }
+  },
+  ModeOptions[] =
+  {
+    { "Undefined", (long) UndefinedMode, MagickTrue },
+    { "Concatenate", (long) ConcatenateMode, MagickFalse },
+    { "Frame", (long) FrameMode, MagickFalse },
+    { "Unframe", (long) UnframeMode, MagickFalse },
+    { (char *) NULL, (long) UndefinedMode, MagickFalse }
+  },
+  NoiseOptions[] =
+  {
+    { "Undefined", (long) UndefinedNoise, MagickTrue },
+    { "Gaussian", (long) (long) GaussianNoise, MagickFalse },
+    { "Impulse", (long) ImpulseNoise, MagickFalse },
+    { "Laplacian", (long) LaplacianNoise, MagickFalse },
+    { "Multiplicative", (long) MultiplicativeGaussianNoise, MagickFalse },
+    { "Poisson", (long) PoissonNoise, MagickFalse },
+    { "Random", (long) RandomNoise, MagickFalse },
+    { "Uniform", (long) UniformNoise, MagickFalse },
+    { (char *) NULL, (long) UndefinedNoise, MagickFalse }
+  },
+  OrientationOptions[] =
+  {
+    { "Undefined", (long) UndefinedOrientation, MagickTrue },
+    { "TopLeft", (long) TopLeftOrientation, MagickFalse },
+    { "TopRight", (long) TopRightOrientation, MagickFalse },
+    { "BottomRight", (long) BottomRightOrientation, MagickFalse },
+    { "BottomLeft", (long) BottomLeftOrientation, MagickFalse },
+    { "LeftTop", (long) LeftTopOrientation, MagickFalse },
+    { "RightTop", (long) RightTopOrientation, MagickFalse },
+    { "RightBottom", (long) RightBottomOrientation, MagickFalse },
+    { "LeftBottom", (long) LeftBottomOrientation, MagickFalse }
+  },
+  PolicyDomainOptions[] =
+  {
+    { "Undefined", (long) UndefinedPolicyDomain, MagickTrue },
+    { "Coder", (long) CoderPolicyDomain, MagickFalse },
+    { "Delegate", (long) DelegatePolicyDomain, MagickFalse },
+    { "Filter", (long) FilterPolicyDomain, MagickFalse },
+    { "Path", (long) PathPolicyDomain, MagickFalse },
+    { "Resource", (long) ResourcePolicyDomain, MagickFalse }
+  },
+  PolicyRightsOptions[] =
+  {
+    { "Undefined", (long) UndefinedPolicyRights, MagickTrue },
+    { "None", (long) NoPolicyRights, MagickFalse },
+    { "Read", (long) ReadPolicyRights, MagickFalse },
+    { "Write", (long) WritePolicyRights, MagickFalse },
+    { "Execute", (long) ExecutePolicyRights, MagickFalse }
+  },
+  PreviewOptions[] =
+  {
+    { "Undefined", (long) UndefinedPreview, MagickTrue },
+    { "AddNoise", (long) AddNoisePreview, MagickFalse },
+    { "Blur", (long) BlurPreview, MagickFalse },
+    { "Brightness", (long) BrightnessPreview, MagickFalse },
+    { "Charcoal", (long) CharcoalDrawingPreview, MagickFalse },
+    { "Despeckle", (long) DespecklePreview, MagickFalse },
+    { "Dull", (long) DullPreview, MagickFalse },
+    { "EdgeDetect", (long) EdgeDetectPreview, MagickFalse },
+    { "Gamma", (long) GammaPreview, MagickFalse },
+    { "Grayscale", (long) GrayscalePreview, MagickFalse },
+    { "Hue", (long) HuePreview, MagickFalse },
+    { "Implode", (long) ImplodePreview, MagickFalse },
+    { "JPEG", (long) JPEGPreview, MagickFalse },
+    { "OilPaint", (long) OilPaintPreview, MagickFalse },
+    { "Quantize", (long) QuantizePreview, MagickFalse },
+    { "Raise", (long) RaisePreview, MagickFalse },
+    { "ReduceNoise", (long) ReduceNoisePreview, MagickFalse },
+    { "Roll", (long) RollPreview, MagickFalse },
+    { "Rotate", (long) RotatePreview, MagickFalse },
+    { "Saturation", (long) SaturationPreview, MagickFalse },
+    { "Segment", (long) SegmentPreview, MagickFalse },
+    { "Shade", (long) ShadePreview, MagickFalse },
+    { "Sharpen", (long) SharpenPreview, MagickFalse },
+    { "Shear", (long) ShearPreview, MagickFalse },
+    { "Solarize", (long) SolarizePreview, MagickFalse },
+    { "Spiff", (long) SpiffPreview, MagickFalse },
+    { "Spread", (long) SpreadPreview, MagickFalse },
+    { "Swirl", (long) SwirlPreview, MagickFalse },
+    { "Threshold", (long) ThresholdPreview, MagickFalse },
+    { "Wave", (long) WavePreview, MagickFalse },
+    { (char *) NULL, (long) UndefinedPreview, MagickFalse }
+  },
+  PrimitiveOptions[] =
+  {
+    { "Undefined", (long) UndefinedPrimitive, MagickTrue },
+    { "Arc", (long) ArcPrimitive, MagickFalse },
+    { "Bezier", (long) BezierPrimitive, MagickFalse },
+    { "Circle", (long) CirclePrimitive, MagickFalse },
+    { "Color", (long) ColorPrimitive, MagickFalse },
+    { "Ellipse", (long) EllipsePrimitive, MagickFalse },
+    { "Image", (long) ImagePrimitive, MagickFalse },
+    { "Line", (long) LinePrimitive, MagickFalse },
+    { "Matte", (long) MattePrimitive, MagickFalse },
+    { "Path", (long) PathPrimitive, MagickFalse },
+    { "Point", (long) PointPrimitive, MagickFalse },
+    { "Polygon", (long) PolygonPrimitive, MagickFalse },
+    { "Polyline", (long) PolylinePrimitive, MagickFalse },
+    { "Rectangle", (long) RectanglePrimitive, MagickFalse },
+    { "roundRectangle", (long) RoundRectanglePrimitive, MagickFalse },
+    { "Text", (long) TextPrimitive, MagickFalse },
+    { (char *) NULL, (long) UndefinedPrimitive, MagickFalse }
+  },
+  QuantumFormatOptions[] =
+  {
+    { "Undefined", (long) UndefinedQuantumFormat, MagickTrue },
+    { "FloatingPoint", (long) FloatingPointQuantumFormat, MagickFalse },
+    { "Signed", (long) SignedQuantumFormat, MagickFalse },
+    { "Unsigned", (long) UnsignedQuantumFormat, MagickFalse },
+    { (char *) NULL, (long) FloatingPointQuantumFormat, MagickFalse }
+  },
+  ResolutionOptions[] =
+  {
+    { "Undefined", (long) UndefinedResolution, MagickTrue },
+    { "PixelsPerInch", (long) PixelsPerInchResolution, MagickFalse },
+    { "PixelsPerCentimeter", (long) PixelsPerCentimeterResolution, MagickFalse },
+    { (char *) NULL, (long) UndefinedResolution, MagickFalse }
+  },
+  ResourceOptions[] =
+  {
+    { "Undefined", (long) UndefinedResource, MagickTrue },
+    { "Area", (long) AreaResource, MagickFalse },
+    { "Disk", (long) DiskResource, MagickFalse },
+    { "File", (long) FileResource, MagickFalse },
+    { "Map", (long) MapResource, MagickFalse },
+    { "Memory", (long) MemoryResource, MagickFalse },
+    { "Thread", (long) ThreadResource, MagickFalse },
+    { "Time", (long) TimeResource, MagickFalse },
+    { (char *) NULL, (long) UndefinedResource, MagickFalse }
+  },
+  SparseColorOptions[] =
+  {
+    { "Undefined", (long) UndefinedDistortion, MagickTrue },
+    { "Barycentric", (long) BarycentricColorInterpolate, MagickFalse },
+    { "Bilinear", (long) BilinearColorInterpolate, MagickFalse },
+    { "Shepards", (long) ShepardsColorInterpolate, MagickFalse },
+    { "Voronoi", (long) VoronoiColorInterpolate, MagickFalse },
+    { (char *) NULL, (long) UndefinedResource, MagickFalse }
+  },
+  StorageOptions[] =
+  {
+    { "Undefined", (long) UndefinedPixel, MagickTrue },
+    { "Char", (long) CharPixel, MagickFalse },
+    { "Double", (long) DoublePixel, MagickFalse },
+    { "Float", (long) FloatPixel, MagickFalse },
+    { "Integer", (long) IntegerPixel, MagickFalse },
+    { "Long", (long) LongPixel, MagickFalse },
+    { "Quantum", (long) QuantumPixel, MagickFalse },
+    { "Short", (long) ShortPixel, MagickFalse },
+    { (char *) NULL, (long) UndefinedResource, MagickFalse }
+  },
+  StretchOptions[] =
+  {
+    { "Undefined", (long) UndefinedStretch, MagickTrue },
+    { "Any", (long) AnyStretch, MagickFalse },
+    { "Condensed", (long) CondensedStretch, MagickFalse },
+    { "Expanded", (long) ExpandedStretch, MagickFalse },
+    { "ExtraCondensed", (long) ExtraCondensedStretch, MagickFalse },
+    { "ExtraExpanded", (long) ExtraExpandedStretch, MagickFalse },
+    { "Normal", (long) NormalStretch, MagickFalse },
+    { "SemiCondensed", (long) SemiCondensedStretch, MagickFalse },
+    { "SemiExpanded", (long) SemiExpandedStretch, MagickFalse },
+    { "UltraCondensed", (long) UltraCondensedStretch, MagickFalse },
+    { "UltraExpanded", (long) UltraExpandedStretch, MagickFalse },
+    { (char *) NULL, (long) UndefinedStretch, MagickFalse }
+  },
+  StyleOptions[] =
+  {
+    { "Undefined", (long) UndefinedStyle, MagickTrue },
+    { "Any", (long) AnyStyle, MagickFalse },
+    { "Italic", (long) ItalicStyle, MagickFalse },
+    { "Normal", (long) NormalStyle, MagickFalse },
+    { "Oblique", (long) ObliqueStyle, MagickFalse },
+    { (char *) NULL, (long) UndefinedStyle, MagickFalse }
+  },
+  TypeOptions[] =
+  {
+    { "Undefined", (long) UndefinedType, MagickTrue },
+    { "Bilevel", (long) BilevelType, MagickFalse },
+    { "ColorSeparation", (long) ColorSeparationType, MagickFalse },
+    { "ColorSeparationMatte", (long) ColorSeparationMatteType, MagickFalse },
+    { "Grayscale", (long) GrayscaleType, MagickFalse },
+    { "GrayscaleMatte", (long) GrayscaleMatteType, MagickFalse },
+    { "Optimize", (long) OptimizeType, MagickFalse },
+    { "Palette", (long) PaletteType, MagickFalse },
+    { "PaletteBilevelMatte", (long) PaletteBilevelMatteType, MagickFalse },
+    { "PaletteMatte", (long) PaletteMatteType, MagickFalse },
+    { "TrueColorMatte", (long) TrueColorMatteType, MagickFalse },
+    { "TrueColor", (long) TrueColorType, MagickFalse },
+    { (char *) NULL, (long) UndefinedType, MagickFalse }
+  },
+  ValidateOptions[] =
+  {
+    { "Undefined", (long) UndefinedValidate, MagickTrue },
+    { "All", (long) AllValidate, MagickFalse },
+    { "Compare", (long) CompareValidate, MagickFalse },
+    { "Composite", (long) CompositeValidate, MagickFalse },
+    { "Convert", (long) ConvertValidate, MagickFalse },
+    { "FormatsInMemory", (long) FormatsInMemoryValidate, MagickFalse },
+    { "FormatsOnDisk", (long) FormatsOnDiskValidate, MagickFalse },
+    { "Identify", (long) IdentifyValidate, MagickFalse },
+    { "ImportExport", (long) ImportExportValidate, MagickFalse },
+    { "Montage", (long) MontageValidate, MagickFalse },
+    { "Stream", (long) StreamValidate, MagickFalse },
+    { "None", (long) NoValidate, MagickFalse },
+    { (char *) NULL, (long) UndefinedValidate, MagickFalse }
+  },
+  VirtualPixelOptions[] =
+  {
+    { "Undefined", (long) UndefinedVirtualPixelMethod, MagickTrue },
+    { "Background", (long) BackgroundVirtualPixelMethod, MagickFalse },
+    { "Black", (long) BlackVirtualPixelMethod, MagickFalse },
+    { "Constant", (long) BackgroundVirtualPixelMethod, MagickTrue }, /* deprecated */
+    { "CheckerTile", (long) CheckerTileVirtualPixelMethod, MagickFalse },
+    { "Dither", (long) DitherVirtualPixelMethod, MagickFalse },
+    { "Edge", (long) EdgeVirtualPixelMethod, MagickFalse },
+    { "Gray", (long) GrayVirtualPixelMethod, MagickFalse },
+    { "HorizontalTile", (long) HorizontalTileVirtualPixelMethod, MagickFalse },
+    { "HorizontalTileEdge", (long) HorizontalTileEdgeVirtualPixelMethod, MagickFalse },
+    { "Mirror", (long) MirrorVirtualPixelMethod, MagickFalse },
+    { "Random", (long) RandomVirtualPixelMethod, MagickFalse },
+    { "Tile", (long) TileVirtualPixelMethod, MagickFalse },
+    { "Transparent", (long) TransparentVirtualPixelMethod, MagickFalse },
+    { "VerticalTile", (long) VerticalTileVirtualPixelMethod, MagickFalse },
+    { "VerticalTileEdge", (long) VerticalTileEdgeVirtualPixelMethod, MagickFalse },
+    { "White", (long) WhiteVirtualPixelMethod, MagickFalse },
+    { (char *) NULL, (long) UndefinedVirtualPixelMethod, 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 M a g i c k O p t i o n s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickOptions() returns a list of values.
+%
+%  The format of the GetMagickOptions method is:
+%
+%      const char **GetMagickOptions(const MagickOption value)
+%
+%  A description of each parameter follows:
+%
+%    o value: the value.
+%
+*/
+
+static const OptionInfo *GetOptionInfo(const MagickOption 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 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 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 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 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 char **GetMagickOptions(const MagickOption value)
+{
+  char
+    **values;
+
+  const OptionInfo
+    *option_info;
+
+  register long
+    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 M a g i c k O p t i o n                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickOption() returns MagickTrue if the option begins with a - or + and
+%  the first character that follows is alphanumeric.
+%
+%  The format of the IsMagickOption method is:
+%
+%      MagickBooleanType IsMagickOption(const char *option)
+%
+%  A description of each parameter follows:
+%
+%    o option: the option.
+%
+*/
+MagickExport MagickBooleanType IsMagickOption(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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k O p t i o n T o M n e m o n i c                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickOptionToMnemonic() returns an enumerated value as a mnemonic.
+%
+%  The format of the MagickOptionToMnemonic method is:
+%
+%      const char *MagickOptionToMnemonic(const MagickOption option,
+%        const long type)
+%
+%  A description of each parameter follows:
+%
+%    o option: the option.
+%
+%    o type: one or more values separated by commas.
+%
+*/
+MagickExport const char *MagickOptionToMnemonic(const MagickOption option,
+  const long type)
+{
+  const OptionInfo
+    *option_info;
+
+  register long
+    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 M a g i c k O p t i o n s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListMagickOptions() lists the contents of enumerated option type(s).
+%
+%  The format of the ListMagickOptions method is:
+%
+%      MagickBooleanType ListMagickOptions(FILE *file,const MagickOption 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 ListMagickOptions(FILE *file,
+  const MagickOption option,ExceptionInfo *magick_unused(exception))
+{
+  const OptionInfo
+    *option_info;
+
+  register long
+    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) fprintf(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:
+%
+%      long ParseChannelOption(const char *channels)
+%
+%  A description of each parameter follows:
+%
+%    o options: One or more values separated by commas.
+%
+*/
+MagickExport long ParseChannelOption(const char *channels)
+{
+  long
+    channel;
+
+  register long
+    i;
+
+  channel=ParseMagickOption(MagickChannelOptions,MagickTrue,channels);
+  if (channel >= 0)
+    return(channel);
+  channel=0;
+  for (i=0; i < (long) 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 'I':
+      case 'i':
+      {
+        channel|=IndexChannel;
+        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 ',':
+      {
+        /*
+          More channel flags follow shorthand.  For example "RGB,sync"
+          Gather the additional channel flags and merge with shorthand
+        */
+        long
+          more_channel;
+        more_channel=ParseMagickOption(MagickChannelOptions,MagickTrue,
+                             channels+i+1);
+        if (more_channel < 0)
+          return(more_channel);
+        channel |= more_channel;
+        return(channel);
+      }
+      default:
+        return(-1);
+    }
+  }
+  return(channel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e M a g i c k O p t i o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseMagickOption() parses a string and returns an enumerated option type(s).
+%
+%  The format of the ParseMagickOption method is:
+%
+%      long ParseMagickOption(const MagickOption 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 long ParseMagickOption(const MagickOption option,
+  const MagickBooleanType list,const char *options)
+{
+  char
+    token[MaxTextExtent];
+
+  const OptionInfo
+    *option_info;
+
+  int
+    sentinel;
+
+  long
+    option_types;
+
+  MagickBooleanType
+    negate;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register long
+    i;
+
+  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)
+        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/magick/option.h b/magick/option.h
new file mode 100644
index 0000000..1f5f932
--- /dev/null
+++ b/magick/option.h
@@ -0,0 +1,152 @@
+/*
+  Copyright 1999-2009 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,
+  MagickDisposeOptions,
+  MagickDistortOptions,
+  MagickDitherOptions,
+  MagickEndianOptions,
+  MagickEvaluateOptions,
+  MagickFillRuleOptions,
+  MagickFilterOptions,
+  MagickFontOptions,
+  MagickFontsOptions,
+  MagickFormatOptions,
+  MagickFunctionOptions,
+  MagickGravityOptions,
+  MagickImageListOptions,
+  MagickIntentOptions,
+  MagickInterlaceOptions,
+  MagickInterpolateOptions,
+  MagickLayerOptions,
+  MagickLineCapOptions,
+  MagickLineJoinOptions,
+  MagickListOptions,
+  MagickLocaleOptions,
+  MagickLogEventOptions,
+  MagickLogOptions,
+  MagickMagicOptions,
+  MagickMethodOptions,
+  MagickMetricOptions,
+  MagickMimeOptions,
+  MagickModeOptions,
+  MagickModuleOptions,
+  MagickNoiseOptions,
+  MagickOrientationOptions,
+  MagickPolicyOptions,
+  MagickPolicyDomainOptions,
+  MagickPolicyRightsOptions,
+  MagickPreviewOptions,
+  MagickPrimitiveOptions,
+  MagickQuantumFormatOptions,
+  MagickResolutionOptions,
+  MagickResourceOptions,
+  MagickSparseColorOptions,
+  MagickStorageOptions,
+  MagickStretchOptions,
+  MagickStyleOptions,
+  MagickThresholdOptions,
+  MagickTypeOptions,
+  MagickValidateOptions,
+  MagickVirtualPixelOptions
+} MagickOption;
+
+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;
+
+  long
+    type;
+
+  MagickBooleanType
+    stealth;
+} OptionInfo;
+
+extern MagickExport char
+  **GetMagickOptions(const MagickOption),
+  *GetNextImageOption(const ImageInfo *),
+  *RemoveImageOption(ImageInfo *,const char *);
+
+extern MagickExport const char
+  *GetImageOption(const ImageInfo *,const char *),
+  *MagickOptionToMnemonic(const MagickOption,const long);
+
+extern MagickExport long
+  ParseChannelOption(const char *),
+  ParseMagickOption(const MagickOption,const MagickBooleanType,const char *);
+
+extern MagickExport MagickBooleanType
+  CloneImageOptions(ImageInfo *,const ImageInfo *),
+  DefineImageOption(ImageInfo *,const char *),
+  DeleteImageOption(ImageInfo *,const char *),
+  IsMagickOption(const char *),
+  ListMagickOptions(FILE *,const MagickOption,ExceptionInfo *),
+  SetImageOption(ImageInfo *,const char *,const char *);
+
+extern MagickExport void
+  DestroyImageOptions(ImageInfo *),
+  ResetImageOptions(const ImageInfo *),
+  ResetImageOptionIterator(const ImageInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/paint.c b/magick/paint.c
new file mode 100644
index 0000000..89e71aa
--- /dev/null
+++ b/magick/paint.c
@@ -0,0 +1,1123 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/draw.h"
+#include "magick/draw-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/paint.h"
+#include "magick/pixel-private.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+
+static inline double MagickMax(const double x,const double y)
+{
+    return( x > y ? x : y);
+}
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 MagickPixelPacket target,const long x_offset,const long 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 MagickPixelPacket *target,const long x_offset,const long 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)) < (long) image->rows)) \
+        { \
+          s->x1=(double) (left); \
+          s->y1=(double) (up); \
+          s->x2=(double) (right); \
+          s->y2=(double) (delta); \
+          s++; \
+        } \
+    } \
+}
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *floodplane_image;
+
+  long
+    offset,
+    start,
+    x,
+    x1,
+    x2,
+    y;
+
+  MagickBooleanType
+    skip;
+
+  MagickPixelPacket
+    fill,
+    pixel;
+
+  PixelPacket
+    fill_color;
+
+  register SegmentInfo
+    *s;
+
+  SegmentInfo
+    *segment_stack;
+
+  /*
+    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 >= (long) image->columns))
+    return(MagickFalse);
+  if ((y_offset < 0) || (y_offset >= (long) 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);
+  GetMagickPixelPacket(image,&fill);
+  GetMagickPixelPacket(image,&pixel);
+  while (s > segment_stack)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Pop segment off stack.
+    */
+    s--;
+    x1=(long) s->x1;
+    x2=(long) s->x2;
+    offset=(long) s->y2;
+    y=(long) s->y1+offset;
+    /*
+      Recolor neighboring pixels.
+    */
+    p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,exception);
+    q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    p+=x1;
+    q+=x1;
+    for (x=x1; x >= 0; x--)
+    {
+      if (q->opacity == (Quantum) TransparentOpacity)
+        break;
+      SetMagickPixelPacket(image,p,indexes+x,&pixel);
+      if (IsMagickColorSimilar(&pixel,target) == invert)
+        break;
+      q->opacity=(Quantum) TransparentOpacity;
+      p--;
+      q--;
+    }
+    if (SyncAuthenticPixels(floodplane_image,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 < (long) image->columns)
+            {
+              p=GetVirtualPixels(image,x,y,image->columns-x,1,exception);
+              q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1,
+                exception);
+              if ((p == (const PixelPacket *) NULL) ||
+                  (q == (PixelPacket *) NULL))
+                break;
+              indexes=GetVirtualIndexQueue(image);
+              for ( ; x < (long) image->columns; x++)
+              {
+                if (q->opacity == (Quantum) TransparentOpacity)
+                  break;
+                SetMagickPixelPacket(image,p,indexes+x,&pixel);
+                if (IsMagickColorSimilar(&pixel,target) == invert)
+                  break;
+                q->opacity=(Quantum) TransparentOpacity;
+                p++;
+                q++;
+              }
+              if (SyncAuthenticPixels(floodplane_image,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=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,exception);
+          q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1,
+            exception);
+          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+            break;
+          indexes=GetVirtualIndexQueue(image);
+          for ( ; x <= x2; x++)
+          {
+            if (q->opacity == (Quantum) TransparentOpacity)
+              break;
+            SetMagickPixelPacket(image,p,indexes+x,&pixel);
+            if (IsMagickColorSimilar(&pixel,target) != invert)
+              break;
+            p++;
+            q++;
+          }
+        }
+      start=x;
+    } while (x <= x2);
+  }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      Tile fill color onto floodplane.
+    */
+    p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,exception);
+    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    indexes=GetAuthenticIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (p->opacity != OpaqueOpacity)
+        {
+          (void) GetFillColor(draw_info,x,y,&fill_color);
+          SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
+          if (image->colorspace == CMYKColorspace)
+            ConvertRGBToCMYK(&fill);
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(fill.red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(fill.green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(fill.blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(fill.opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            indexes[x]=RoundToQuantum(fill.index);
+        }
+      p++;
+      q++;
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+  }
+  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
+  floodplane_image=DestroyImage(floodplane_image);
+  return(y == (long) 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.
+%
+% This provides a good example of making use of the DrawGradientImage
+% function and the gradient structure in draw_info.
+*/
+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 long
+    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 < (long) gradient->number_stops; i++)
+    GetMagickPixelPacket(image,&gradient->stops[i].color);
+  SetMagickPixelPacket(image,start_color,(IndexPacket *) NULL,
+    &gradient->stops[0].color);
+  gradient->stops[0].offset=0.0;
+  SetMagickPixelPacket(image,stop_color,(IndexPacket *) NULL,
+    &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->opacity == OpaqueOpacity) &&
+      (stop_color->opacity == OpaqueOpacity))
+    image->matte=MagickFalse;
+  if ((IsGrayPixel(start_color) != MagickFalse) &&
+      (IsGrayPixel(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 unsigned long **DestroyHistogramThreadSet(unsigned long **histogram)
+{
+  register long
+    i;
+
+  assert(histogram != (unsigned long **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (histogram[i] != (unsigned long *) NULL)
+      histogram[i]=(unsigned long *) RelinquishMagickMemory(histogram[i]);
+  histogram=(unsigned long **) RelinquishAlignedMemory(histogram);
+  return(histogram);
+}
+
+static unsigned long **AcquireHistogramThreadSet(const size_t count)
+{
+  register long
+    i;
+
+  unsigned long
+    **histogram,
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  histogram=(unsigned long **) AcquireAlignedMemory(number_threads,
+    sizeof(*histogram));
+  if (histogram == (unsigned long **) NULL)
+    return((unsigned long **) NULL);
+  (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
+  for (i=0; i < (long) number_threads; i++)
+  {
+    histogram[i]=(unsigned long *) AcquireQuantumMemory(count,
+      sizeof(**histogram));
+    if (histogram[i] == (unsigned long *) NULL)
+      return(DestroyHistogramThreadSet(histogram));
+  }
+  return(histogram);
+}
+
+MagickExport Image *OilPaintImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+#define NumberPaintBins  256
+#define OilPaintImageTag  "OilPaint/Image"
+
+  Image
+    *paint_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  unsigned long
+    **histograms,
+    width;
+
+  CacheView
+    *image_view,
+    *paint_view;
+
+  /*
+    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);
+  if ((image->columns < width) || (image->rows < width))
+    ThrowImageException(OptionError,"ImageSmallerThanRadius");
+  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 == (unsigned long **) 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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict paint_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    register unsigned long
+      *histogram;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
+      2L),image->columns+width,width,exception);
+    q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    paint_indexes=GetCacheViewAuthenticIndexQueue(paint_view);
+    histogram=histograms[GetOpenMPThreadId()];
+    for (x=0; x < (long) image->columns; x++)
+    {
+      long
+        j,
+        k,
+        v;
+
+      register long
+        i,
+        u;
+
+      unsigned long
+        count;
+
+      /*
+        Assign most frequent color.
+      */
+      i=0;
+      j=0;
+      count=0;
+      (void) ResetMagickMemory(histogram,0,NumberPaintBins*sizeof(*histogram));
+      for (v=0; v < (long) width; v++)
+      {
+        for (u=0; u < (long) width; u++)
+        {
+          k=(long) ScaleQuantumToChar(PixelIntensityToQuantum(p+u+i));
+          histogram[k]++;
+          if (histogram[k] > count)
+            {
+              j=i+u;
+              count=histogram[k];
+            }
+        }
+        i+=image->columns+width;
+      }
+      *q=(*(p+j));
+      if (image->colorspace == CMYKColorspace)
+        paint_indexes[x]=indexes[x+j];
+      p++;
+      q++;
+    }
+    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 MagickPixelPacket *target,const MagickPixelPacket *fill,
+  const MagickBooleanType invert)
+{
+  return(OpaquePaintImageChannel(image,AllChannels,target,fill,invert));
+}
+
+MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
+  const ChannelType channel,const MagickPixelPacket *target,
+  const MagickPixelPacket *fill,const MagickBooleanType invert)
+{
+#define OpaquePaintImageTag  "Opaque/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  CacheView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(target != (MagickPixelPacket *) NULL);
+  assert(fill != (MagickPixelPacket *) 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);
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,q,indexes+x,&pixel);
+      if (IsMagickColorSimilar(&pixel,target) != invert)
+        {
+          if ((channel & RedChannel) != 0)
+            q->red=RoundToQuantum(fill->red);
+          if ((channel & GreenChannel) != 0)
+            q->green=RoundToQuantum(fill->green);
+          if ((channel & BlueChannel) != 0)
+            q->blue=RoundToQuantum(fill->blue);
+          if ((channel & OpacityChannel) != 0)
+            q->opacity=RoundToQuantum(fill->opacity);
+          if (((channel & IndexChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            indexes[x]=RoundToQuantum(fill->index);
+        }
+      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_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 MagickPixelPacket *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 MagickPixelPacket *target,const Quantum opacity,
+  const MagickBooleanType invert)
+{
+#define TransparentPaintImageTag  "Transparent/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  CacheView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(target != (MagickPixelPacket *) 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);
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,q,indexes+x,&pixel);
+      if (IsMagickColorSimilar(&pixel,target) != invert)
+        q->opacity=opacity;
+      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_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 MagickPixelPacket *low,const MagickPixelPacket *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 MagickPixelPacket *low,const MagickPixelPacket *high,
+  const Quantum opacity,const MagickBooleanType invert)
+{
+#define TransparentPaintImageTag  "Transparent/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(high != (MagickPixelPacket *) NULL);
+  assert(low != (MagickPixelPacket *) 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,ResetAlphaChannel);
+  /*
+    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 < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      match;
+
+    MagickPixelPacket
+      pixel;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    GetMagickPixelPacket(image,&pixel);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,q,indexes+x,&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)
+        q->opacity=opacity;
+      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_TransparentPaintImageChroma)
+#endif
+        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/magick/paint.h b/magick/paint.h
new file mode 100644
index 0000000..c011d72
--- /dev/null
+++ b/magick/paint.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2009 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 "magick/color.h"
+#include "magick/draw.h"
+
+extern MagickExport Image
+  *OilPaintImage(const Image *,const double,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  FloodfillPaintImage(Image *,const ChannelType,const DrawInfo *,
+    const MagickPixelPacket *,const long,const long,const MagickBooleanType),
+  GradientImage(Image *,const GradientType,const SpreadMethod,
+    const PixelPacket *,const PixelPacket *),
+  OpaquePaintImage(Image *,const MagickPixelPacket *,const MagickPixelPacket *,
+    const MagickBooleanType),
+  OpaquePaintImageChannel(Image *,const ChannelType,const MagickPixelPacket *,
+    const MagickPixelPacket *,const MagickBooleanType),
+  TransparentPaintImage(Image *,const MagickPixelPacket *,
+    const Quantum,const MagickBooleanType),
+  TransparentPaintImageChroma(Image *,const MagickPixelPacket *,
+    const MagickPixelPacket *,const Quantum,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/pixel-private.h b/magick/pixel-private.h
new file mode 100644
index 0000000..5772646
--- /dev/null
+++ b/magick/pixel-private.h
@@ -0,0 +1,103 @@
+/*
+  Copyright 1999-2009 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 *) AcquireMagickMemory(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 ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(MagickTrue);
+#else
+  if ((fabs(pixel->red-pixel->green) <= MagickEpsilon) &&
+      (fabs(pixel->green-pixel->blue) <= MagickEpsilon))
+    return(MagickTrue);
+#endif
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsMonochromePixel(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
+  if (((fabs(pixel->red) <= MagickEpsilon) ||
+       (fabs(pixel->red-QuantumRange) <= MagickEpsilon)) &&
+      (fabs(pixel->red-pixel->green) <= MagickEpsilon) &&
+      (fabs(pixel->green-pixel->blue) <= MagickEpsilon))
+    return(MagickTrue);
+#endif
+  return(MagickFalse);
+}
+
+static inline void SetMagickPixelPacket(const Image *image,
+  const PixelPacket *color,const IndexPacket *index,MagickPixelPacket *pixel)
+{
+  pixel->red=(MagickRealType) color->red;
+  pixel->green=(MagickRealType) color->green;
+  pixel->blue=(MagickRealType) color->blue;
+  pixel->opacity=(MagickRealType) color->opacity;
+  if (((image->colorspace == CMYKColorspace) ||
+       (image->storage_class == PseudoClass)) &&
+      (index != (const IndexPacket *) NULL))
+    pixel->index=(MagickRealType) *index;
+}
+
+static inline void SetPixelPacket(const Image *image,
+  const MagickPixelPacket *pixel,PixelPacket *color,IndexPacket *index)
+{
+  color->red=RoundToQuantum(pixel->red);
+  color->green=RoundToQuantum(pixel->green);
+  color->blue=RoundToQuantum(pixel->blue);
+  color->opacity=RoundToQuantum(pixel->opacity);
+  if (((image->colorspace == CMYKColorspace) ||
+       (image->storage_class == PseudoClass)) &&
+      (index != (const IndexPacket *) NULL))
+    *index=RoundToQuantum(pixel->index);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/pixel.c b/magick/pixel.c
new file mode 100644
index 0000000..1142e2c
--- /dev/null
+++ b/magick/pixel.c
@@ -0,0 +1,3374 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/color-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/cache.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/statistic.h"
+#include "magick/stream.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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, long, 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 long x_offset,const long y_offset,const unsigned long columns,
+%        const unsigned long 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 long x_offset,const long y_offset,const unsigned long columns,
+  const unsigned long rows,const char *map,const StorageType type,void *pixels,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  QuantumType
+    *quantum_map;
+
+  register long
+    i,
+    x;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  size_t
+    length;
+
+  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 < (long) 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 < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->blue);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->blue);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->red);
+              *q++=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->blue);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->red);
+              *q++=ScaleQuantumToChar((Quantum) 0);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->red);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->red);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->blue);
+              *q++=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(p->red);
+              *q++=ScaleQuantumToChar(p->green);
+              *q++=ScaleQuantumToChar(p->blue);
+              *q++=ScaleQuantumToChar((Quantum) 0);
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToChar(p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToChar(p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToChar(p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToChar(p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToChar(indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case DoublePixel:
+    {
+      register double
+        *q;
+
+      q=(double *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->blue);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->blue);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->red);
+              *q++=(double) (QuantumScale*((Quantum) (QuantumRange-
+                p->opacity)));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->blue);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->red);
+              *q++=0.0;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->red);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->red);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->blue);
+              *q++=(double) (QuantumScale*((Quantum) (QuantumRange-
+                p->opacity)));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(double) (QuantumScale*p->red);
+              *q++=(double) (QuantumScale*p->green);
+              *q++=(double) (QuantumScale*p->blue);
+              *q++=0.0;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(double) (QuantumScale*p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(double) (QuantumScale*p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(double) (QuantumScale*p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(double) (QuantumScale*((Quantum) (QuantumRange-
+                  p->opacity)));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(double) (QuantumScale*p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(double) (QuantumScale*indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(double) (QuantumScale*PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case FloatPixel:
+    {
+      register float
+        *q;
+
+      q=(float *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->blue);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->blue);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->red);
+              *q++=(float) (QuantumScale*(Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->blue);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->red);
+              *q++=0.0;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->red);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->red);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->blue);
+              *q++=(float) (QuantumScale*((Quantum) (QuantumRange-p->opacity)));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(float) (QuantumScale*p->red);
+              *q++=(float) (QuantumScale*p->green);
+              *q++=(float) (QuantumScale*p->blue);
+              *q++=0.0;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(float) (QuantumScale*p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(float) (QuantumScale*p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(float) (QuantumScale*p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(float) (QuantumScale*((Quantum) (QuantumRange-p->opacity)));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(float) (QuantumScale*p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(float) (QuantumScale*indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(float) (QuantumScale*PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case IntegerPixel:
+    {
+      register unsigned int
+        *q;
+
+      q=(unsigned int *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              *q++=(unsigned int) ScaleQuantumToLong((Quantum) (QuantumRange-
+                p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              *q++=0U;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int)
+                ScaleQuantumToLong(PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              *q++=(unsigned int) ScaleQuantumToLong((Quantum)
+                (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(p->red);
+              *q++=(unsigned int) ScaleQuantumToLong(p->green);
+              *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+              *q++=0U;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong((Quantum) (QuantumRange-
+                  p->opacity));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(unsigned int) ScaleQuantumToLong(indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(unsigned int)
+                  ScaleQuantumToLong(PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register unsigned long
+        *q;
+
+      q=(unsigned long *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->blue);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->blue);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->red);
+              *q++=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->blue);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->red);
+              *q++=0;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->red);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->red);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->blue);
+              *q++=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(p->red);
+              *q++=ScaleQuantumToLong(p->green);
+              *q++=ScaleQuantumToLong(p->blue);
+              *q++=0;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToLong(p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToLong(p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToLong(p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToLong(p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToLong(indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToLong(PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case QuantumPixel:
+    {
+      register Quantum
+        *q;
+
+      q=(Quantum *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->blue;
+              *q++=p->green;
+              *q++=p->red;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->blue;
+              *q++=p->green;
+              *q++=p->red;
+              *q++=(Quantum) (QuantumRange-p->opacity);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->blue;
+              *q++=p->green;
+              *q++=p->red;
+              *q++=(Quantum) 0;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=PixelIntensityToQuantum(p);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->red;
+              *q++=p->green;
+              *q++=p->blue;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->red;
+              *q++=p->green;
+              *q++=p->blue;
+              *q++=(Quantum) (QuantumRange-p->opacity);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=p->red;
+              *q++=p->green;
+              *q++=p->blue;
+              *q++=(Quantum) 0;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=(Quantum) 0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=p->red;
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=p->green;
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=p->blue;
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(Quantum) (QuantumRange-p->opacity);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=p->opacity;
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=indexes[x];
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                *q=(Quantum) 0;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      break;
+    }
+    case ShortPixel:
+    {
+      register unsigned short
+        *q;
+
+      q=(unsigned short *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->blue);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->red);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->blue);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->red);
+              *q++=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->blue);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->red);
+              *q++=0;
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->red);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->blue);
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->red);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->blue);
+              *q++=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+              p++;
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(p->red);
+              *q++=ScaleQuantumToShort(p->green);
+              *q++=ScaleQuantumToShort(p->blue);
+              *q++=0;
+              p++;
+            }
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToShort(p->red);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToShort(p->green);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToShort(p->blue);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToShort(p->opacity);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToShort(indexes[x]);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p++;
+        }
+      }
+      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                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickPixelPacket() initializes the MagickPixelPacket structure.
+%
+%  The format of the GetMagickPixelPacket method is:
+%
+%      GetMagickPixelPacket(const Image *image,MagickPixelPacket *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o pixel: Specifies a pointer to a PixelPacket structure.
+%
+*/
+MagickExport void GetMagickPixelPacket(const Image *image,
+  MagickPixelPacket *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->opacity=(MagickRealType) OpaqueOpacity;
+  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, long, 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 long x_offset,
+%        const long y_offset,const unsigned long columns,
+%        const unsigned long 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 long x_offset,const long y_offset,const unsigned long columns,
+  const unsigned long rows,const char *map,const StorageType type,
+  const void *pixels)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  PixelPacket
+    *q;
+
+  QuantumType
+    *quantum_map;
+
+  register IndexPacket
+    *indexes;
+
+  register long
+    i,
+    x;
+
+  size_t
+    length;
+
+  /*
+    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 < (long) 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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->red=ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->red=ScaleCharToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRO") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->red=ScaleCharToQuantum(*p++);
+              q->opacity=ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->red=ScaleCharToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleCharToQuantum(*p++);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->blue=ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->blue=ScaleCharToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBO") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->blue=ScaleCharToQuantum(*p++);
+              q->opacity=ScaleCharToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleCharToQuantum(*p++);
+              q->green=ScaleCharToQuantum(*p++);
+              q->blue=ScaleCharToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=ScaleCharToQuantum(*p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=ScaleCharToQuantum(*p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=ScaleCharToQuantum(*p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-ScaleCharToQuantum(*p);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=ScaleCharToQuantum(*p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=ScaleCharToQuantum(*p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=ScaleCharToQuantum(*p);
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->opacity=(Quantum) QuantumRange-RoundToQuantum((MagickRealType)
+                QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              q->green=q->red;
+              q->blue=q->red;
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->opacity=(Quantum) QuantumRange-RoundToQuantum((MagickRealType)
+                QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-RoundToQuantum(
+                  (MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->opacity=(Quantum) QuantumRange-RoundToQuantum((MagickRealType)
+                QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              q->green=q->red;
+              q->blue=q->red;
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->opacity=(Quantum) QuantumRange-RoundToQuantum((MagickRealType)
+                QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-RoundToQuantum(
+                  (MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=RoundToQuantum((MagickRealType) QuantumRange*(*p));
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=ScaleLongToQuantum(*p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=ScaleLongToQuantum(*p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=ScaleLongToQuantum(*p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=ScaleLongToQuantum(*p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=ScaleLongToQuantum(*p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=ScaleLongToQuantum(*p);
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register const unsigned long
+        *p;
+
+      p=(const unsigned long *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->red=ScaleLongToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleLongToQuantum(*p++);
+              q->green=ScaleLongToQuantum(*p++);
+              q->blue=ScaleLongToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=ScaleLongToQuantum(*p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=ScaleLongToQuantum(*p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=ScaleLongToQuantum(*p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-ScaleLongToQuantum(*p);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=ScaleLongToQuantum(*p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=ScaleLongToQuantum(*p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=ScaleLongToQuantum(*p);
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=(*p++);
+              q->green=(*p++);
+              q->red=(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=(*p++);
+              q->green=(*p++);
+              q->red=(*p++);
+              q->opacity=(Quantum) QuantumRange-(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=(*p++);
+              q->green=(*p++);
+              q->red=(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=(*p++);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=(*p++);
+              q->green=(*p++);
+              q->blue=(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=(*p++);
+              q->green=(*p++);
+              q->blue=(*p++);
+              q->opacity=(Quantum) QuantumRange-(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=(*p++);
+              q->green=(*p++);
+              q->blue=(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=(*p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=(*p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=(*p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-(*p);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=(*p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=(*p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=(*p);
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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 < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->red=ScaleShortToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->red=ScaleShortToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleShortToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->blue=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->red=ScaleShortToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleShortToQuantum(*p++);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->blue=ScaleShortToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->blue=ScaleShortToQuantum(*p++);
+              q->opacity=(Quantum) QuantumRange-ScaleShortToQuantum(*p++);
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (long) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            for (x=0; x < (long) columns; x++)
+            {
+              q->red=ScaleShortToQuantum(*p++);
+              q->green=ScaleShortToQuantum(*p++);
+              q->blue=ScaleShortToQuantum(*p++);
+              p++;
+              q++;
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (long) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetAuthenticIndexQueue(image);
+        for (x=0; x < (long) columns; x++)
+        {
+          for (i=0; i < (long) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                q->red=ScaleShortToQuantum(*p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                q->green=ScaleShortToQuantum(*p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                q->blue=ScaleShortToQuantum(*p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                q->opacity=(Quantum) QuantumRange-ScaleShortToQuantum(*p);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                q->opacity=ScaleShortToQuantum(*p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                indexes[x]=ScaleShortToQuantum(*p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                q->red=ScaleShortToQuantum(*p);
+                q->green=q->red;
+                q->blue=q->red;
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q++;
+        }
+        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);
+}
diff --git a/magick/pixel.h b/magick/pixel.h
new file mode 100644
index 0000000..ed567cf
--- /dev/null
+++ b/magick/pixel.h
@@ -0,0 +1,95 @@
+/*
+  Copyright 1999-2009 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 <magick/colorspace.h>
+#include <magick/constitute.h>
+
+typedef struct _LongPixelPacket
+{
+  unsigned long
+    red,
+    green,
+    blue,
+    opacity,
+    index;
+} LongPixelPacket;
+
+typedef struct _MagickPixelPacket
+{
+  ClassType
+    storage_class;
+
+  ColorspaceType
+    colorspace;
+
+  MagickBooleanType
+    matte;
+
+  double
+    fuzz;
+
+  unsigned long
+    depth;
+
+  MagickRealType
+    red,
+    green,
+    blue,
+    opacity,
+    index;
+} MagickPixelPacket;
+
+typedef Quantum IndexPacket;
+
+typedef struct _PixelPacket
+{
+#if defined(MAGICKCORE_WORDS_BIGENDIAN)
+  Quantum
+    red,
+    green,
+    blue,
+    opacity;
+#else
+  Quantum
+    blue,
+    green,
+    red,
+    opacity;
+#endif
+} PixelPacket;
+
+extern MagickExport MagickBooleanType
+  ExportImagePixels(const Image *,const long,const long,const unsigned long,
+    const unsigned long,const char *,const StorageType,void *,ExceptionInfo *),
+  ImportImagePixels(Image *,const long,const long,const unsigned long,
+    const unsigned long,const char *,const StorageType,const void *);
+
+extern MagickExport void
+  GetMagickPixelPacket(const Image *,MagickPixelPacket *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/policy.c b/magick/policy.c
new file mode 100644
index 0000000..e4cc4d8
--- /dev/null
+++ b/magick/policy.c
@@ -0,0 +1,936 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/policy.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define PolicyFilename  "policy.xml"
+
+/*
+  Declare policy map.
+*/
+static const char
+  *PolicyMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<policymap>"
+    "</policymap>";
+
+/*
+  Domaindef declarations.
+*/
+struct _PolicyInfo
+{
+  char
+    *path,
+    *name;
+
+  PolicyDomain
+    domain;
+
+  PolicyRights
+    rights;
+
+  char
+    *pattern,
+    *value;
+
+  MagickBooleanType
+    stealth,
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    signature;
+};
+
+/*
+  Static declarations.
+*/
+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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P o l i c y L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPolicyList() deallocates memory associated with the policy list.
+%
+%  The format of the DestroyPolicyList method is:
+%
+%      DestroyPolicyList(void)
+%
+*/
+
+static void *DestroyPolicyElement(void *policy_info)
+{
+  register PolicyInfo
+    *p;
+
+  p=(PolicyInfo *) policy_info;
+  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 DestroyPolicyList(void)
+{
+  AcquireSemaphoreInfo(&policy_semaphore);
+  if (policy_list != (LinkedListInfo *) NULL)
+    policy_list=DestroyLinkedList(policy_list,DestroyPolicyElement);
+  instantiate_policy=MagickFalse;
+  RelinquishSemaphoreInfo(policy_semaphore);
+  DestroySemaphoreInfo(&policy_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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.
+  */
+  AcquireSemaphoreInfo(&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) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+      "UnrecognizedPolicy","`%s'",name);
+  else
+    (void) InsertValueInLinkedList(policy_list,0,
+      RemoveElementByValueFromLinkedList(policy_list,p));
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_policies,ExceptionInfo *exception)
+{
+  const PolicyInfo
+    **policies;
+
+  register const PolicyInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate policy list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_policies != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(policy_semaphore);
+  policies[i]=(PolicyInfo *) NULL;
+  *number_policies=(unsigned long) 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,unsigned long *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,
+  unsigned long *number_policies,ExceptionInfo *exception)
+{
+  char
+    **policies;
+
+  register const PolicyInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate policy list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_policies != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(policy_semaphore);
+  policies[i]=(char *) NULL;
+  *number_policies=(unsigned long) 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))
+    {
+      AcquireSemaphoreInfo(&policy_semaphore);
+      if ((policy_list == (LinkedListInfo *) NULL) &&
+          (instantiate_policy == MagickFalse))
+        {
+          (void) LoadPolicyLists(PolicyFilename,exception);
+          instantiate_policy=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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\" ...",
+    MagickOptionToMnemonic(MagickPolicyDomainOptions,domain),
+    MagickOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
+  exception=AcquireExceptionInfo();
+  policy_info=GetPolicyInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  if (policy_info == (PolicyInfo *) NULL)
+    return(MagickTrue);
+  authorized=MagickTrue;
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(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 long
+    i;
+
+  unsigned long
+    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 < (long) 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) fprintf(file,"\nPath: %s\n",policy_info[i]->path);
+    path=policy_info[i]->path;
+    domain=MagickOptionToMnemonic(MagickPolicyDomainOptions,
+      policy_info[i]->domain);
+    (void) fprintf(file,"  Policy: %s\n",domain);
+    if (policy_info[i]->domain == ResourcePolicyDomain)
+      {
+        if (policy_info[i]->name != (char *) NULL)
+          (void) fprintf(file,"    name: %s\n",policy_info[i]->name);
+        if (policy_info[i]->value != (char *) NULL)
+          (void) fprintf(file,"    value: %s\n",policy_info[i]->value);
+      }
+    else
+      {
+        (void) fprintf(file,"    rights: ");
+        if (policy_info[i]->rights == NoPolicyRights)
+          (void) fprintf(file,"None ");
+        if ((policy_info[i]->rights & ReadPolicyRights) != 0)
+          (void) fprintf(file,"Read ");
+        if ((policy_info[i]->rights & WritePolicyRights) != 0)
+          (void) fprintf(file,"Write ");
+        if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
+          (void) fprintf(file,"Execute ");
+        (void) fprintf(file,"\n");
+        if (policy_info[i]->pattern != (char *) NULL)
+          (void) fprintf(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 unsigned long 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 unsigned long 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->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) ParseMagickOption(
+              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) ParseMagickOption(
+              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)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadPolicyList(PolicyMap,"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|=LoadPolicyList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((policy_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(policy_list) != MagickFalse))
+    status|=LoadPolicyList(PolicyMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
diff --git a/magick/policy.h b/magick/policy.h
new file mode 100644
index 0000000..d8ad7bd
--- /dev/null
+++ b/magick/policy.h
@@ -0,0 +1,68 @@
+/*
+  Copyright 1999-2009 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 <magick/pixel.h>
+#include <magick/exception.h>
+
+typedef enum
+{
+  UndefinedPolicyDomain,
+  CoderPolicyDomain,
+  DelegatePolicyDomain,
+  FilterPolicyDomain,
+  PathPolicyDomain,
+  ResourcePolicyDomain
+} 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 *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport const PolicyInfo
+  **GetPolicyInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  IsRightsAuthorized(const PolicyDomain,const PolicyRights,const char *),
+  ListPolicyInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyPolicyList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/prepress.c b/magick/prepress.c
new file mode 100644
index 0000000..139382a
--- /dev/null
+++ b/magick/prepress.c
@@ -0,0 +1,153 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/cache-view.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/image.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/prepress.h"
+#include "magick/registry.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/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)
+{
+  double
+    total_ink_density;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+  {
+    double
+      density;
+
+    register const IndexPacket
+      *indexes;
+
+    register const PixelPacket
+      *p;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      density=(double) p->red+p->green+p->blue+indexes[x];
+      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++;
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    total_ink_density=0.0;
+  return(total_ink_density);
+}
diff --git a/magick/prepress.h b/magick/prepress.h
new file mode 100644
index 0000000..023e16a
--- /dev/null
+++ b/magick/prepress.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2009 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/magick/profile.c b/magick/profile.c
new file mode 100644
index 0000000..cafda02
--- /dev/null
+++ b/magick/profile.c
@@ -0,0 +1,1943 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
+#include <lcms/lcms.h>
+#else
+#include "lcms.h"
+#endif
+#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);
+  if (LocaleCompare(name,"icc") == 0)
+    {
+      /*
+        Continue to support deprecated color profile for now.
+      */
+      image->color_profile.length=0;
+      image->color_profile.info=(unsigned char *) NULL;
+    }
+  if (LocaleCompare(name,"iptc") == 0)
+    {
+      /*
+        Continue to support deprecated IPTC profile for now.
+      */
+      image->iptc_profile.length=0;
+      image->iptc_profile.info=(unsigned char *) NULL;
+    }
+  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 long
+    i;
+
+  assert(pixels != (unsigned short **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (unsigned short *) NULL)
+      pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
+  pixels=(unsigned short **) RelinquishAlignedMemory(pixels);
+  return(pixels);
+}
+
+static unsigned short **AcquirePixelThreadSet(const size_t columns,
+  const size_t channels)
+{
+  register long
+    i;
+
+  unsigned short
+    **pixels;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(unsigned short **) AcquireAlignedMemory(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 < (long) 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 long
+    i;
+
+  assert(transform != (cmsHTRANSFORM *) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (transform[i] != (cmsHTRANSFORM) NULL)
+      cmsDeleteTransform(transform[i]);
+  transform=(cmsHTRANSFORM *) RelinquishAlignedMemory(transform);
+  return(transform);
+}
+
+static cmsHTRANSFORM *AcquireTransformThreadSet(
+  const cmsHPROFILE source_profile,const DWORD source_type,
+  const cmsHPROFILE target_profile,const DWORD target_type,const int intent,
+  const DWORD flags)
+{
+  cmsHTRANSFORM
+    *transform;
+
+  register long
+    i;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  transform=(cmsHTRANSFORM *) AcquireAlignedMemory(number_threads,
+    sizeof(*transform));
+  if (transform == (cmsHTRANSFORM *) NULL)
+    return((cmsHTRANSFORM *) NULL);
+  (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
+  for (i=0; i < (long) number_threads; i++)
+  {
+    transform[i]=cmsCreateTransform(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 > 1010)
+static int LCMSErrorHandler(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) \
+{ \
+  (void) cmsCloseProfile(source_profile); \
+  (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 long
+        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 < 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 < number_arguments; i++)
+        arguments[i]=DestroyString(arguments[i]);
+      arguments=(char **) RelinquishMagickMemory(arguments);
+      return(MagickTrue);
+    }
+  /*
+    Add a ICC, IPTC, or generic profile to the image.
+  */
+  profile=AcquireStringInfo((size_t) length);
+  SetStringInfoDatum(profile,(unsigned char *) datum);
+  if ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0))
+    {
+      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
+      if (icc_profile == (StringInfo *) NULL)
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          ImageWarning,"AssociateProfile","`%s'",name);
+      else
+        {
+          CacheView
+            *image_view;
+
+          ColorspaceType
+            source_colorspace,
+            target_colorspace;
+
+          cmsHPROFILE
+            source_profile,
+            target_profile;
+
+          cmsHTRANSFORM
+            *transform;
+
+          DWORD
+            flags,
+            source_type,
+            target_type;
+
+          ExceptionInfo
+            *exception;
+
+          int
+            intent;
+
+          long
+            progress,
+            y;
+
+          MagickBooleanType
+            status;
+
+          size_t
+            length,
+            source_channels,
+            target_channels;
+
+          unsigned short
+            **source_pixels,
+            **target_pixels;
+
+          /*
+            Transform pixel colors as defined by the color profiles.
+          */
+#if defined(LCMS_VERSION) && (LCMS_VERSION > 1010)
+          cmsSetErrorHandler(LCMSErrorHandler);
+#else
+          (void) cmsErrorAction(LCMS_ERROR_SHOW);
+#endif
+          source_profile=cmsOpenProfileFromMem(GetStringInfoDatum(icc_profile),
+            (DWORD) GetStringInfoLength(icc_profile));
+          target_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
+            (DWORD) GetStringInfoLength(profile));
+          if ((source_profile == (cmsHPROFILE) NULL) ||
+              (target_profile == (cmsHPROFILE) NULL))
+            ThrowBinaryException(ResourceLimitError,
+              "ColorspaceColorProfileMismatch",name);
+          switch (cmsGetColorSpace(source_profile))
+          {
+            case icSigCmykData:
+            {
+              source_colorspace=CMYKColorspace;
+              source_type=(DWORD) TYPE_CMYK_16;
+              source_channels=4;
+              break;
+            }
+            case icSigGrayData:
+            {
+              source_colorspace=GRAYColorspace;
+              source_type=(DWORD) TYPE_GRAY_16;
+              source_channels=1;
+              break;
+            }
+            case icSigLabData:
+            {
+              source_colorspace=LabColorspace;
+              source_type=(DWORD) TYPE_Lab_16;
+              source_channels=3;
+              break;
+            }
+            case icSigLuvData:
+            {
+              source_colorspace=YUVColorspace;
+              source_type=(DWORD) TYPE_YUV_16;
+              source_channels=3;
+              break;
+            }
+            case icSigRgbData:
+            {
+              source_colorspace=RGBColorspace;
+              source_type=(DWORD) TYPE_RGB_16;
+              source_channels=3;
+              break;
+            }
+            case icSigXYZData:
+            {
+              source_colorspace=XYZColorspace;
+              source_type=(DWORD) TYPE_XYZ_16;
+              source_channels=3;
+              break;
+            }
+            case icSigYCbCrData:
+            {
+              source_colorspace=YCbCrColorspace;
+              source_type=(DWORD) TYPE_YCbCr_16;
+              source_channels=3;
+              break;
+            }
+            default:
+            {
+              source_colorspace=UndefinedColorspace;
+              source_type=(DWORD) TYPE_RGB_16;
+              source_channels=3;
+              break;
+            }
+          }
+          switch (cmsGetColorSpace(target_profile))
+          {
+            case icSigCmykData:
+            {
+              target_colorspace=CMYKColorspace;
+              target_type=(DWORD) TYPE_CMYK_16;
+              target_channels=4;
+              break;
+            }
+            case icSigLabData:
+            {
+              target_colorspace=LabColorspace;
+              target_type=(DWORD) TYPE_Lab_16;
+              target_channels=3;
+              break;
+            }
+            case icSigGrayData:
+            {
+              target_colorspace=GRAYColorspace;
+              target_type=(DWORD) TYPE_GRAY_16;
+              target_channels=1;
+              break;
+            }
+            case icSigLuvData:
+            {
+              target_colorspace=YUVColorspace;
+              target_type=(DWORD) TYPE_YUV_16;
+              target_channels=3;
+              break;
+            }
+            case icSigRgbData:
+            {
+              target_colorspace=RGBColorspace;
+              target_type=(DWORD) TYPE_RGB_16;
+              target_channels=3;
+              break;
+            }
+            case icSigXYZData:
+            {
+              target_colorspace=XYZColorspace;
+              target_type=(DWORD) TYPE_XYZ_16;
+              target_channels=3;
+              break;
+            }
+            case icSigYCbCrData:
+            {
+              target_colorspace=YCbCrColorspace;
+              target_type=(DWORD) TYPE_YCbCr_16;
+              target_channels=3;
+              break;
+            }
+            default:
+            {
+              target_colorspace=UndefinedColorspace;
+              target_type=(DWORD) TYPE_RGB_16;
+              target_channels=3;
+              break;
+            }
+          }
+          exception=(&image->exception);
+          if ((source_colorspace == UndefinedColorspace) ||
+              (target_colorspace == UndefinedColorspace))
+            ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+              name);
+           if ((source_colorspace == GRAYColorspace) &&
+               (IsGrayImage(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(source_profile,source_type,
+            target_profile,target_type,intent,flags);
+          (void) cmsCloseProfile(source_profile);
+          if (transform == (cmsHTRANSFORM *) NULL)
+            ThrowBinaryException(ImageError,"UnableToCreateColorTransform",
+              name);
+          /*
+            Transform image as dictated by the source and target image profiles.
+          */
+          length=(size_t) image->columns;
+          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);
+              (void) cmsCloseProfile(target_profile);
+              ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+                image->filename);
+            }
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            {
+              target_pixels=DestroyPixelThreadSet(target_pixels);
+              source_pixels=DestroyPixelThreadSet(source_pixels);
+              transform=DestroyTransformThreadSet(transform);
+              (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 < (long) image->rows; y++)
+          {
+            MagickBooleanType
+              sync;
+
+            register IndexPacket
+              *__restrict indexes;
+
+            register long
+              id,
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            register unsigned short
+              *p;
+
+            if (status == MagickFalse)
+              continue;
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (PixelPacket *) NULL)
+              {
+                status=MagickFalse;
+                continue;
+              }
+            indexes=GetCacheViewAuthenticIndexQueue(image_view);
+            id=GetOpenMPThreadId();
+            p=source_pixels[id];
+            for (x=0; x < (long) image->columns; x++)
+            {
+              *p++=ScaleQuantumToShort(q->red);
+              if (source_channels > 1)
+                {
+                  *p++=ScaleQuantumToShort(q->green);
+                  *p++=ScaleQuantumToShort(q->blue);
+                }
+              if (source_channels > 3)
+                *p++=ScaleQuantumToShort(indexes[x]);
+              q++;
+            }
+            cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
+              (unsigned int) image->columns);
+            p=target_pixels[id];
+            q-=image->columns;
+            for (x=0; x < (long) image->columns; x++)
+            {
+              q->red=ScaleShortToQuantum(*p);
+              q->green=q->red;
+              q->blue=q->red;
+              p++;
+              if (target_channels > 1)
+                {
+                  q->green=ScaleShortToQuantum(*p);
+                  p++;
+                  q->blue=ScaleShortToQuantum(*p);
+                  p++;
+                }
+              if (target_channels > 3)
+                {
+                  indexes[x]=ScaleShortToQuantum(*p);
+                  p++;
+                }
+              q++;
+            }
+            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 (cmsGetColorSpace(target_profile))
+          {
+            case icSigRgbData:
+            {
+              image->type=image->matte == MagickFalse ? TrueColorType :
+                TrueColorMatteType;
+              break;
+            }
+            case icSigCmykData:
+            {
+              image->type=image->matte == MagickFalse ? ColorSeparationType :
+                ColorSeparationMatteType;
+              break;
+            }
+            case icSigGrayData:
+            {
+              image->type=image->matte == MagickFalse ? GrayscaleType :
+                GrayscaleMatteType;
+              break;
+            }
+            default:
+              break;
+          }
+          target_pixels=DestroyPixelThreadSet(target_pixels);
+          source_pixels=DestroyPixelThreadSet(source_pixels);
+          transform=DestroyTransformThreadSet(transform);
+          (void) cmsCloseProfile(target_profile);
+        }
+#endif
+    }
+  status=SetImageProfile(image,name,profile);
+  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);
+  if (LocaleCompare(name,"icc") == 0)
+    {
+      /*
+        Continue to support deprecated color profile for now.
+      */
+      image->color_profile.length=0;
+      image->color_profile.info=(unsigned char *) NULL;
+    }
+  if (LocaleCompare(name,"iptc") == 0)
+    {
+      /*
+        Continue to support deprecated IPTC profile for now.
+      */
+      image->iptc_profile.length=0;
+      image->iptc_profile.info=(unsigned char *) 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,
+  unsigned long *quantum)
+{
+  *quantum=(unsigned long) (*p++ << 24);
+  *quantum|=(unsigned long) (*p++ << 16);
+  *quantum|=(unsigned long) (*p++ << 8);
+  *quantum|=(unsigned long) (*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;
+
+  unsigned long
+    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,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
+    {
+      const StringInfo
+        *icc_profile;
+
+      /*
+        Continue to support deprecated color profile member.
+      */
+      icc_profile=GetImageProfile(image,name);
+      if (icc_profile != (const StringInfo *) NULL)
+        {
+          image->color_profile.length=GetStringInfoLength(icc_profile);
+          image->color_profile.info=GetStringInfoDatum(icc_profile);
+        }
+    }
+  if ((status != MagickFalse) &&
+      ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
+    {
+      const StringInfo
+        *iptc_profile;
+
+      /*
+        Continue to support deprecated IPTC profile member.
+      */
+      iptc_profile=GetImageProfile(image,name);
+      if (iptc_profile != (const StringInfo *) NULL)
+        {
+          image->iptc_profile.length=GetStringInfoLength(iptc_profile);
+          image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
+        }
+      (void) GetProfilesFromResourceBlock(image,profile);
+    }
+  /*
+    Inject profile into image properties.
+  */
+  (void) FormatMagickString(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 unsigned long ReadProfileLong(const EndianType endian,
+  unsigned char *buffer)
+{
+  unsigned long
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
+        (buffer[2] << 8) | buffer[3]);
+      return((unsigned long) (value & 0xffffffff));
+    }
+  value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
+    (buffer[1] << 8 ) | (buffer[0]));
+  return((unsigned long) (value & 0xffffffff));
+}
+
+static inline void WriteProfileLong(const EndianType endian,
+  const unsigned long 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;
+
+    unsigned long
+      entry;
+  } DirectoryInfo;
+
+  DirectoryInfo
+    directory_stack[MaxDirectoryStack];
+
+  EndianType
+    endian;
+
+  long
+    id,
+    level;
+
+  size_t
+    length;
+
+  ssize_t
+    offset;
+
+  static int
+    format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
+
+  StringInfo
+    *profile;
+
+  unsigned char
+    *directory,
+    *exif;
+
+  unsigned long
+    entry,
+    number_entries;
+
+  /*
+    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=(int) 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=(ssize_t) 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++)
+    {
+      long
+        components,
+        format,
+        tag_value;
+
+      register unsigned char
+        *p,
+        *q;
+
+      size_t
+        number_bytes;
+
+      q=(unsigned char *) (directory+2+(12*entry));
+      tag_value=(long) ReadProfileShort(endian,q);
+      format=(long) ReadProfileShort(endian,q+2);
+      if ((format-1) >= EXIF_NUM_FORMATS)
+        break;
+      components=(long) ReadProfileLong(endian,q+4);
+      number_bytes=(size_t) components*format_bytes[format];
+      if (number_bytes <= 4)
+        p=q+8;
+      else
+        {
+          ssize_t
+            offset;
+
+          /*
+            The directory entry contains an offset.
+          */
+          offset=(ssize_t) 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,(unsigned long)
+            (image->x_resolution+0.5),p);
+          (void) WriteProfileLong(endian,1UL,p+4);
+          break;
+        }
+        case 0x011b:
+        {
+          (void) WriteProfileLong(endian,(unsigned long)
+            (image->y_resolution+0.5),p);
+          (void) WriteProfileLong(endian,1UL,p+4);
+          break;
+        }
+        case 0x0112:
+        {
+          (void) WriteProfileShort(endian,(unsigned short)
+            image->orientation,p);
+          (void) WriteProfileLong(endian,1UL,p+4);
+          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/magick/profile.h b/magick/profile.h
new file mode 100644
index 0000000..c18c95f
--- /dev/null
+++ b/magick/profile.h
@@ -0,0 +1,75 @@
+/*
+  Copyright 1999-2009 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 "magick/string_.h"
+
+typedef struct _ProfileInfo
+{
+  char
+    *name;
+
+  size_t
+    length;
+
+  unsigned char
+    *info;
+
+  unsigned long
+    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/magick/property.c b/magick/property.c
new file mode 100644
index 0000000..155b4ae
--- /dev/null
+++ b/magick/property.c
@@ -0,0 +1,3462 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/compare.h"
+#include "magick/constitute.h"
+#include "magick/draw.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/fx.h"
+#include "magick/fx-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/montage.h"
+#include "magick/option.h"
+#include "magick/profile.h"
+#include "magick/property.h"
+#include "magick/quantum.h"
+#include "magick/resource_.h"
+#include "magick/splay-tree.h"
+#include "magick/signature-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/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 proporty.
+%
+%  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 FormatImagePropertyList(Image *image,
+  const char *property,const char *format,va_list operands)
+{
+  char
+    value[MaxTextExtent];
+
+  int
+    n;
+
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(value,MaxTextExtent,format,operands);
+#else
+  n=vsprintf(value,format,operands);
+#endif
+  if (n < 0)
+    value[MaxTextExtent-1]='\0';
+  return(SetImageProperty(image,property,value));
+}
+
+MagickExport MagickBooleanType FormatImageProperty(Image *image,
+  const char *property,const char *format,...)
+{
+  MagickBooleanType
+    status;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  status=FormatImagePropertyList(image,property,format,operands);
+  va_end(operands);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long,
+    const unsigned long),
+  *TraceSVGClippath(const unsigned char *,size_t,const unsigned long,
+    const unsigned long);
+
+static MagickBooleanType GetIPTCProperty(const Image *image,const char *key)
+{
+  char
+    *attribute,
+    *message;
+
+  const StringInfo
+    *profile;
+
+  long
+    count,
+    dataset,
+    record;
+
+  register long
+    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 < (long) GetStringInfoLength(profile); i+=(long) length)
+  {
+    length=1;
+    if ((long) 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 long MagickMax(const long x,const long 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 unsigned long ReadPropertyMSBLong(const unsigned char **p,
+  size_t *length)
+{
+  int
+    c;
+
+  register long
+    i;
+
+  unsigned char
+    buffer[4];
+
+  unsigned long
+    value;
+
+  if (*length < 4)
+    return(~0UL);
+  for (i=0; i < 4; i++)
+  {
+    c=(int) (*(*p)++);
+    (*length)--;
+    buffer[i]=(unsigned char) c;
+  }
+  value=(unsigned long) (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 long
+    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
+    id,
+    start,
+    stop,
+    sub_number;
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  ssize_t
+    count;
+
+  size_t
+    length;
+
+  /*
+    There's 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=atol(&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=(long) ReadPropertyMSBShort(&info,&length);
+    if (id < start)
+      continue;
+    if (id > 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)
+          resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
+            sizeof(*resource));
+        if (resource != (char *) NULL)
+          {
+            for (i=0; i < (long) count; i++)
+              resource[i]=(char) ReadPropertyByte(&info,&length);
+            resource[count]='\0';
+          }
+      }
+    if ((count & 0x01) == 0)
+      (void) ReadPropertyByte(&info,&length);
+    count=(ssize_t) 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)
+      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 unsigned long ReadPropertyLong(const EndianType endian,
+  const unsigned char *buffer)
+{
+  unsigned long
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
+        (buffer[2] << 8) | buffer[3]);
+      return((unsigned long) (value & 0xffffffff));
+    }
+  value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
+    (buffer[1] << 8 ) | (buffer[0]));
+  return((unsigned long) (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) \
+{ \
+   long \
+     component; \
+ \
+   size_t \
+     length; \
+ \
+   unsigned char \
+     *p1; \
+ \
+   length=0; \
+   p1=p; \
+   for (component=0; component < components; component++) \
+   { \
+     length+=FormatMagickString(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) \
+{ \
+   long \
+     component; \
+ \
+   size_t \
+     length; \
+ \
+   unsigned char \
+     *p1; \
+ \
+   length=0; \
+   p1=p; \
+   for (component=0; component < components; component++) \
+   { \
+     length+=FormatMagickString(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;
+
+    unsigned long
+      entry,
+      offset;
+  } DirectoryInfo;
+
+  typedef struct _TagInfo
+  {
+    unsigned long
+      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" },
+      { 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;
+
+  long
+    all,
+    id,
+    level,
+    tag_value;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  ssize_t
+    offset;
+
+  static int
+    tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
+
+  unsigned long
+    entry,
+    number_entries,
+    tag_offset,
+    tag;
+
+  /*
+    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=(long) 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=(unsigned long) 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=(long) 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) ReadPropertyLong(endian,exif+4);
+  if ((size_t) offset >= length)
+    return(MagickFalse);
+  /*
+    Set the pointer to the first IFD and follow it were it leads.
+  */
+  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++)
+    {
+      long
+        components;
+
+      register unsigned char
+        *p,
+        *q;
+
+      size_t
+        number_bytes;
+
+      unsigned long
+        format;
+
+      q=(unsigned char *) (directory+2+(12*entry));
+      tag_value=(long) ReadPropertyShort(endian,q)+tag_offset;
+      format=(unsigned long) ReadPropertyShort(endian,q+2);
+      if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes)))
+        break;
+      components=(long) 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) ReadPropertyLong(endian,q+8);
+          if ((size_t) (offset+number_bytes) > length)
+            continue;
+          p=(unsigned char *) (exif+offset);
+        }
+      if ((all != 0) || (tag == (unsigned long) tag_value))
+        {
+          char
+            buffer[MaxTextExtent],
+            *value;
+
+          switch (format)
+          {
+            case EXIF_FMT_BYTE:
+            case EXIF_FMT_UNDEFINED:
+            {
+              EXIFMultipleValues(1,"%lu",(unsigned long)
+                (*(unsigned char *) p1));
+              break;
+            }
+            case EXIF_FMT_SBYTE:
+            {
+              EXIFMultipleValues(1,"%ld",(long) (*(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,"%lu",ReadPropertyLong(endian,p1));
+              break;
+            }
+            case EXIF_FMT_SLONG:
+            {
+              EXIFMultipleValues(4,"%ld",ReadPropertyLong(endian,p1));
+              break;
+            }
+            case EXIF_FMT_URATIONAL:
+            {
+              EXIFMultipleFractions(8,"%ld/%ld",ReadPropertyLong(endian,p1),
+                ReadPropertyLong(endian,p1+4));
+              break;
+            }
+            case EXIF_FMT_SRATIONAL:
+            {
+              EXIFMultipleFractions(8,"%ld/%ld",ReadPropertyLong(endian,p1),
+                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 long
+                    i;
+
+                  for (i=0; i < (long) 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 long
+                    i;
+
+                  description="unknown";
+                  for (i=0; ; i++)
+                  {
+                    if (EXIFTag[i].tag == 0)
+                      break;
+                    if ((long) EXIFTag[i].tag == tag_value)
+                      {
+                        description=EXIFTag[i].description;
+                        break;
+                      }
+                  }
+                  (void) FormatMagickString(key,MaxTextExtent,"%s",
+                    description);
+                  break;
+                }
+                case 2:
+                {
+                  if (tag_value < 0x10000)
+                    (void) FormatMagickString(key,MaxTextExtent,"#%04lx",
+                      tag_value);
+                  else
+                    if (tag_value < 0x20000)
+                      (void) FormatMagickString(key,MaxTextExtent,"@%04lx",
+                        tag_value & 0xffff);
+                    else
+                      (void) FormatMagickString(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);
+            }
+        }
+        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)))
+              {
+                unsigned long
+                  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(MagickTrue);
+}
+
+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 unsigned long magick_unused(columns),
+  const unsigned long magick_unused(rows))
+{
+  char
+    *path,
+    *message;
+
+  long
+    knot_count,
+    selector,
+    y;
+
+  MagickBooleanType
+    in_subpath;
+
+  PointInfo
+    first[3],
+    last[3],
+    point[3];
+
+  register long
+    i,
+    x;
+
+  path=AcquireString((char *) NULL);
+  if (path == (char *) NULL)
+    return((char *) NULL);
+  message=AcquireString((char *) NULL);
+  (void) FormatMagickString(message,MaxTextExtent,"/ClipImage\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"{\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"  /c {curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"  /l {lineto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"  /m {moveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "  /v {currentpoint 6 2 roll curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "  /y {2 copy curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "  /z {closepath} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(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=(long) ReadPropertyMSBShort(&blob,&length);
+    switch (selector)
+    {
+      case 0:
+      case 3:
+      {
+        if (knot_count != 0)
+          {
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Expected subpath length record.
+        */
+        knot_count=(long) 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++)
+        {
+          y=(long) ReadPropertyMSBLong(&blob,&length);
+          x=(long) ReadPropertyMSBLong(&blob,&length);
+          point[i].x=(double) x/4096/4096;
+          point[i].y=1.0-(double) y/4096/4096;
+        }
+        if (in_subpath == MagickFalse)
+          {
+            (void) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,
+                    "  %g %g %g %g y\n",last[2].x,last[2].y,point[1].x,
+                    point[1].y);
+                else
+                  (void) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,
+                    "  %g %g %g %g y z\n",last[2].x,last[2].y,first[1].x,
+                    first[1].y);
+                else
+                  (void) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,"  eoclip\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"} bind def");
+  (void) ConcatenateString(&path,message);
+  message=DestroyString(message);
+  return(path);
+}
+
+static char *TraceSVGClippath(const unsigned char *blob,size_t length,
+  const unsigned long columns,const unsigned long rows)
+{
+  char
+    *path,
+    *message;
+
+  long
+    knot_count,
+    selector,
+    x,
+    y;
+
+  MagickBooleanType
+    in_subpath;
+
+  PointInfo
+    first[3],
+    last[3],
+    point[3];
+
+  register long
+    i;
+
+  path=AcquireString((char *) NULL);
+  if (path == (char *) NULL)
+    return((char *) NULL);
+  message=AcquireString((char *) NULL);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "<svg width=\"%lu\" height=\"%lu\">\n",columns,rows);
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"<g>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,
+    "<path style=\"fill:#00000000;stroke:#00000000;");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(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=(long) ReadPropertyMSBShort(&blob,&length);
+    switch (selector)
+    {
+      case 0:
+      case 3:
+      {
+        if (knot_count != 0)
+          {
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Expected subpath length record.
+        */
+        knot_count=(long) 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;
+          }
+        else
+          {
+            /*
+              Add sub-path knot
+            */
+            for (i=0; i < 3; i++)
+            {
+              y=(long) ReadPropertyMSBLong(&blob,&length);
+              x=(long) ReadPropertyMSBLong(&blob,&length);
+              point[i].x=(double) x*columns/4096/4096;
+              point[i].y=(double) y*rows/4096/4096;
+            }
+            if (in_subpath == MagickFalse)
+              {
+                (void) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,"L %g,%g\n",
+                    point[1].x,point[1].y);
+                else
+                  (void) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,"L %g,%g Z\n",
+                    first[1].x,first[1].y);
+                else
+                  {
+                    (void) FormatMagickString(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) FormatMagickString(message,MaxTextExtent,"\"/>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(message,MaxTextExtent,"</g>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatMagickString(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 (property == (const char *) NULL)
+    {
+      ResetSplayTreeIterator((SplayTreeInfo *) image->properties);
+      p=(const char *) GetNextValueInSplayTree((SplayTreeInfo *)
+        image->properties);
+      return(p);
+    }
+  if ((image->properties != (void *) NULL) &&
+      (LocaleNCompare("fx:",property,3) != 0))
+    {
+      p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+        image->properties,property);
+      if (p != (const char *) NULL)
+        return(p);
+    }
+  if (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)
+            {
+              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)
+            {
+              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=FxEvaluateExpression(fx_info,&alpha,exception);
+          fx_info=DestroyFxInfo(fx_info);
+          if (status != MagickFalse)
+            {
+              char
+                value[MaxTextExtent];
+
+              (void) FormatMagickString(value,MaxTextExtent,"%g",(double)
+                alpha);
+              (void) SetImageProperty((Image *) image,property,value);
+            }
+          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)
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    case 'P':
+    case 'p':
+    {
+      if (LocaleNCompare("pixel:",property,6) == 0)
+        {
+          MagickPixelPacket
+            pixel;
+
+          GetMagickPixelPacket(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;
+          status|=FxEvaluateChannelExpression(fx_info,OpacityChannel,0,0,&alpha,
+            exception);
+          pixel.opacity=(MagickRealType) QuantumRange*(1.0-alpha);
+          if (image->colorspace == CMYKColorspace)
+            {
+              status|=FxEvaluateChannelExpression(fx_info,BlackChannel,0,0,
+                &alpha,exception);
+              pixel.index=(MagickRealType) QuantumRange*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)
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      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) FormatMagickString(value,MaxTextExtent,"%s",
+            MagickOptionToMnemonic(MagickColorspaceOptions,(long)
+            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 (IsGrayImage(image,&image->exception) != MagickFalse)
+            colorspace=GRAYColorspace;
+          (void) FormatMagickString(value,MaxTextExtent,"%s",
+            MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace));
+          break;
+        }
+      break;
+    }
+    case 'd':
+    {
+      if (LocaleNCompare("depth",property,5) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",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) FormatMagickString(value,MaxTextExtent,"0x%lx",
+            image_info->group);
+          break;
+        }
+      break;
+    }
+    case 'h':
+    {
+      if (LocaleNCompare("height",property,6) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",
+            image->magick_rows != 0 ? image->magick_rows : 256UL);
+          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) FormatMagickString(value,MaxTextExtent,"%g",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) FormatMagickString(value,MaxTextExtent,"%g",maximum);
+          break;
+        }
+      if (LocaleNCompare("mean",property,4) == 0)
+        {
+          double
+            mean,
+            standard_deviation;
+
+          (void) GetImageChannelMean(image,image_info->channel,&mean,
+            &standard_deviation,&image->exception);
+          (void) FormatMagickString(value,MaxTextExtent,"%g",mean);
+          break;
+        }
+      if (LocaleNCompare("min",property,3) == 0)
+        {
+          double
+            maximum,
+            minimum;
+
+          (void) GetImageChannelRange(image,image_info->channel,&minimum,
+            &maximum,&image->exception);
+          (void) FormatMagickString(value,MaxTextExtent,"%g",minimum);
+          break;
+        }
+      break;
+    }
+    case 'n':
+    {
+      if (LocaleNCompare("name",property,4) == 0)
+        {
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+     break;
+    }
+    case 'o':
+    {
+      if (LocaleNCompare("output",property,6) == 0)
+        {
+          (void) CopyMagickString(value,image_info->filename,MaxTextExtent);
+          break;
+        }
+     break;
+    }
+    case 'p':
+    {
+      if (LocaleNCompare("page",property,4) == 0)
+        {
+          register const Image
+            *p;
+
+          unsigned long
+            page;
+
+          p=image;
+          for (page=1; GetPreviousImageInList(p) != (Image *) NULL; page++)
+            p=GetPreviousImageInList(p);
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",page);
+          break;
+        }
+      break;
+    }
+    case 's':
+    {
+      if (LocaleNCompare("size",property,4) == 0)
+        {
+          char
+            format[MaxTextExtent];
+
+          (void) FormatMagickSize(GetBlobSize(image),format);
+          (void) FormatMagickString(value,MaxTextExtent,"%s",format);
+          break;
+        }
+      if (LocaleNCompare("scenes",property,6) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",
+            (unsigned long) GetImageListLength(image));
+          break;
+        }
+      if (LocaleNCompare("scene",property,5) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",image->scene);
+          if (image_info->number_scenes != 0)
+            (void) FormatMagickString(value,MaxTextExtent,"%lu",
+              image_info->scene);
+          break;
+        }
+      if (LocaleNCompare("skewness",property,8) == 0)
+        {
+          double
+            kurtosis,
+            skewness;
+
+          (void) GetImageChannelKurtosis(image,image_info->channel,&kurtosis,
+            &skewness,&image->exception);
+          (void) FormatMagickString(value,MaxTextExtent,"%g",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) FormatMagickString(value,MaxTextExtent,"%g",
+            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 'w':
+    {
+      if (LocaleNCompare("width",property,5) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%lu",
+            image->magick_columns != 0 ? image->magick_columns : 256UL);
+          break;
+        }
+      break;
+    }
+    case 'x':
+    {
+      if (LocaleNCompare("xresolution",property,11) == 0)
+        {
+          (void) FormatMagickString(value,MaxTextExtent,"%g",
+            image->x_resolution);
+          break;
+        }
+      break;
+    }
+    case 'y':
+    {
+      if (LocaleNCompare("yresolution",property,11) == 0)
+        {
+          (void) FormatMagickString(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;
+
+  ImageInfo
+    *text_info;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register long
+    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.
+  */
+  text_info=CloneImageInfo(image_info);
+  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];
+
+        MagickSizeType
+          length;
+
+        /*
+          File size.
+        */
+        length=GetBlobSize(image);
+        (void) FormatMagickString(format,MaxTextExtent,"%lu",(unsigned long)
+          length);
+        if (length != (MagickSizeType) ((size_t) length))
+          (void) FormatMagickSize(length,format);
+        q+=ConcatenateMagickString(q,format,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+=FormatMagickString(q,extent,"%lux%lu%+ld%+ld",image->page.width,
+          image->page.height,image->page.x,image->page.y);
+        break;
+      }
+      case 'h':
+      {
+        /*
+          Image height.
+        */
+        q+=FormatMagickString(q,extent,"%lu",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+=FormatMagickString(q,extent,"%lu",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+=FormatMagickString(q,extent,"%lu",(unsigned long)
+          GetImageListLength(image));
+        break;
+      }
+      case 'o':
+      {
+        /*
+          Image output filename.
+        */
+        q+=CopyMagickString(q,text_info->filename,extent);
+        break;
+      }
+      case 'p':
+      {
+        register const Image
+          *p;
+
+        unsigned long
+          page;
+
+        /*
+          Image page number.
+        */
+        p=image;
+        for (page=1; GetPreviousImageInList(p) != (Image *) NULL; page++)
+          p=GetPreviousImageInList(p);
+        q+=FormatMagickString(q,extent,"%lu",page);
+        break;
+      }
+      case 'q':
+      {
+        /*
+          Image depth.
+        */
+        q+=FormatMagickString(q,extent,"%lu",image->depth);
+        break;
+      }
+      case 'r':
+      {
+        ColorspaceType
+          colorspace;
+
+        /*
+          Image storage class and colorspace.
+        */
+        colorspace=image->colorspace;
+        if (IsGrayImage(image,&image->exception) != MagickFalse)
+          colorspace=GRAYColorspace;
+        q+=FormatMagickString(q,extent,"%s%s%s",MagickOptionToMnemonic(
+          MagickClassOptions,(long) image->storage_class),
+          MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace),
+          image->matte != MagickFalse ? "Matte" : "");
+        break;
+      }
+      case 's':
+      {
+        /*
+          Image scene number.
+        */
+        if (text_info->number_scenes == 0)
+          q+=FormatMagickString(q,extent,"%lu",image->scene);
+        else
+          q+=FormatMagickString(q,extent,"%lu",text_info->scene);
+        break;
+      }
+      case 'u':
+      {
+        /*
+          Unique filename.
+        */
+        (void) CopyMagickString(filename,text_info->unique,extent);
+        q+=CopyMagickString(q,filename,extent);
+        break;
+      }
+      case 'w':
+      {
+        /*
+          Image width.
+        */
+        q+=FormatMagickString(q,extent,"%lu",image->columns != 0 ?
+          image->columns : image->magick_columns);
+        break;
+      }
+      case 'x':
+      {
+        /*
+          Image horizontal resolution.
+        */
+        q+=FormatMagickString(q,extent,"%g %s",image->x_resolution,
+          MagickOptionToMnemonic(MagickResolutionOptions,(long) image->units));
+        break;
+      }
+      case 'y':
+      {
+        /*
+          Image vertical resolution.
+        */
+        q+=FormatMagickString(q,extent,"%g %s",image->y_resolution,
+          MagickOptionToMnemonic(MagickResolutionOptions,(long) image->units));
+        break;
+      }
+      case 'z':
+      {
+        /*
+          Image depth.
+        */
+        q+=FormatMagickString(q,extent,"%lu",image->depth);
+        break;
+      }
+      case 'A':
+      {
+        /*
+          Image alpha channel.
+        */
+        q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
+          MagickBooleanOptions,(long) image->matte));
+        break;
+      }
+      case 'C':
+      {
+        /*
+          Image compression method.
+        */
+        q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
+          MagickCompressOptions,(long) image->compression));
+        break;
+      }
+      case 'D':
+      {
+        /*
+          Image dispose method.
+        */
+        q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
+          MagickDisposeOptions,(long) image->dispose));
+        break;
+      }
+      case 'G':
+      {
+        q+=FormatMagickString(q,extent,"%lux%lu",image->magick_columns,
+          image->magick_rows);
+        break;
+      }
+      case 'H':
+      {
+        q+=FormatMagickString(q,extent,"%ld",image->page.height);
+        break;
+      }
+      case 'O':
+      {
+        q+=FormatMagickString(q,extent,"%+ld%+ld",image->page.x,image->page.y);
+        break;
+      }
+      case 'P':
+      {
+        q+=FormatMagickString(q,extent,"%lux%lu",image->page.width,
+          image->page.height);
+        break;
+      }
+      case 'Q':
+      {
+        q+=FormatMagickString(q,extent,"%lu",image->quality);
+        break;
+      }
+      case 'S':
+      {
+        /*
+          Image scenes.
+        */
+        if (text_info->number_scenes == 0)
+          q+=CopyMagickString(q,"2147483647",extent);
+        else
+          q+=FormatMagickString(q,extent,"%lu",text_info->scene+
+            text_info->number_scenes);
+        break;
+      }
+      case 'T':
+      {
+        q+=FormatMagickString(q,extent,"%lu",image->delay);
+        break;
+      }
+      case 'W':
+      {
+        q+=FormatMagickString(q,extent,"%ld",image->page.width);
+        break;
+      }
+      case 'X':
+      {
+        q+=FormatMagickString(q,extent,"%+ld",image->page.x);
+        break;
+      }
+      case 'Y':
+      {
+        q+=FormatMagickString(q,extent,"%+ld",image->page.y);
+        break;
+      }
+      case 'Z':
+      {
+        /*
+          Unique filename.
+        */
+        (void) CopyMagickString(filename,text_info->zero,extent);
+        q+=CopyMagickString(q,filename,extent);
+        break;
+      }
+      case '[':
+      {
+        char
+          pattern[MaxTextExtent];
+
+        const char
+          *key,
+          *value;
+
+        long
+          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+=FormatMagickString(q,extent,"%s=%s\n",key,value);
+                      }
+                  }
+                key=GetNextImageProperty(image);
+              }
+            }
+        value=GetMagickProperty(text_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;
+          }
+        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;
+      }
+      case '@':
+      {
+        RectangleInfo
+          page;
+
+        /*
+          Image bounding box.
+        */
+        page=GetImageBoundingBox(image,&image->exception);
+        q+=FormatMagickString(q,MaxTextExtent,"%lux%lu%+ld%+ld",page.width,
+          page.height,page.x,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';
+  text_info=DestroyImageInfo(text_info);
+  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)
+{
+  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;
+  switch (*property)
+  {
+    case 'B':
+    case 'b':
+    {
+      if (LocaleCompare(property,"bias") == 0)
+        {
+          image->bias=StringToDouble(value,QuantumRange);
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'C':
+    case 'c':
+    {
+      if (LocaleCompare(property,"colorspace") == 0)
+        {
+          long
+            colorspace;
+
+          colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
+            value);
+          if (colorspace < 0)
+            break;
+          (void) SetImageColorspace(image,(ColorspaceType) colorspace);
+          break;
+        }
+      if (LocaleCompare(property,"compose") == 0)
+        {
+          long
+            compose;
+
+          compose=ParseMagickOption(MagickComposeOptions,MagickFalse,value);
+          if (compose < 0)
+            break;
+          image->compose=(CompositeOperator) compose;
+          break;
+        }
+      if (LocaleCompare(property,"compress") == 0)
+        {
+          long
+            compression;
+
+          compression=ParseMagickOption(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 > (unsigned long) (geometry_info.rho+0.5))
+                image->delay=(unsigned long) (geometry_info.rho+0.5);
+            }
+          else
+            if ((flags & LessValue) != 0)
+              {
+                if (image->delay < (unsigned long) (geometry_info.rho+0.5))
+                  image->ticks_per_second=(long) (geometry_info.sigma+0.5);
+              }
+            else
+              image->delay=(unsigned long) (geometry_info.rho+0.5);
+          if ((flags & SigmaValue) != 0)
+            image->ticks_per_second=(long) (geometry_info.sigma+0.5);
+          break;
+        }
+      if (LocaleCompare(property,"depth") == 0)
+        {
+          image->depth=(unsigned long) atol(value);
+          break;
+        }
+      if (LocaleCompare(property,"dispose") == 0)
+        {
+          long
+            dispose;
+
+          dispose=ParseMagickOption(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)
+        {
+          long
+            gravity;
+
+          gravity=ParseMagickOption(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)
+        {
+          long
+            rendering_intent;
+
+          rendering_intent=ParseMagickOption(MagickIntentOptions,MagickFalse,
+            value);
+          if (rendering_intent < 0)
+            break;
+          image->rendering_intent=(RenderingIntent) rendering_intent;
+          break;
+        }
+      if (LocaleCompare(property,"interpolate") == 0)
+        {
+          long
+            interpolate;
+
+          interpolate=ParseMagickOption(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=(unsigned long) atol(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;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'R':
+    case 'r':
+    {
+      if (LocaleCompare(property,"rendering-intent") == 0)
+        {
+          long
+            rendering_intent;
+
+          rendering_intent=ParseMagickOption(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;
+    }
+    default:
+    {
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+  }
+  return(status);
+}
diff --git a/magick/property.h b/magick/property.h
new file mode 100644
index 0000000..95715b0
--- /dev/null
+++ b/magick/property.h
@@ -0,0 +1,52 @@
+/*
+  Copyright 1999-2009 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))),
+  FormatImagePropertyList(Image *,const char *,const char *,va_list)
+    magick_attribute((format (printf,3,0))),
+  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/magick/quantize.c b/magick/quantize.c
new file mode 100644
index 0000000..584e815
--- /dev/null
+++ b/magick/quantize.c
@@ -0,0 +1,3134 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/option.h"
+#include "magick/pixel-private.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/string_.h"
+
+/*
+  Define declarations.
+*/
+#define CacheShift  2
+#define ErrorQueueLength  16
+#define MaxNodes  266817
+#define MaxTreeDepth  8
+#define NodesInAList  1920
+
+/*
+  Typdef declarations.
+*/
+typedef struct _RealPixelPacket
+{
+  MagickRealType
+    red,
+    green,
+    blue,
+    opacity;
+} RealPixelPacket;
+
+typedef struct _NodeInfo
+{
+  struct _NodeInfo
+    *parent,
+    *child[16];
+
+  MagickSizeType
+    number_unique;
+
+  RealPixelPacket
+    total_color;
+
+  MagickRealType
+    quantize_error;
+
+  unsigned long
+    color_number,
+    id,
+    level;
+} NodeInfo;
+
+typedef struct _Nodes
+{
+  NodeInfo
+    *nodes;
+
+  struct _Nodes
+    *next;
+} Nodes;
+
+typedef struct _CubeInfo
+{
+  NodeInfo
+    *root;
+
+  unsigned long
+    colors,
+    maximum_colors;
+
+  long
+    transparent_index;
+
+  MagickSizeType
+    transparent_pixels;
+
+  RealPixelPacket
+    target;
+
+  MagickRealType
+    distance,
+    pruning_threshold,
+    next_threshold;
+
+  unsigned long
+    nodes,
+    free_nodes,
+    color_number;
+
+  NodeInfo
+    *next_node;
+
+  Nodes
+    *node_queue;
+
+  long
+    *cache;
+
+  RealPixelPacket
+    error[ErrorQueueLength];
+
+  MagickRealType
+    weights[ErrorQueueLength];
+
+  QuantizeInfo
+    *quantize_info;
+
+  MagickBooleanType
+    associate_alpha;
+
+  long
+    x,
+    y;
+
+  unsigned long
+    depth;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    span;
+} CubeInfo;
+
+/*
+  Method prototypes.
+*/
+static CubeInfo
+  *GetCubeInfo(const QuantizeInfo *,const unsigned long,const unsigned long);
+
+static NodeInfo
+  *GetNodeInfo(CubeInfo *,const unsigned long,const unsigned long,NodeInfo *);
+
+static MagickBooleanType
+  AssignImageColors(Image *,CubeInfo *),
+  ClassifyImageColors(CubeInfo *,const Image *,ExceptionInfo *),
+  DitherImage(Image *,CubeInfo *),
+  SetGrayscaleImage(Image *);
+
+static unsigned long
+  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) ParseMagickOption(
+          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 CubeInfo *cube_info,
+  const PixelPacket *pixel,RealPixelPacket *alpha_pixel)
+{
+  MagickRealType
+    alpha;
+
+  if ((cube_info->associate_alpha == MagickFalse) ||
+      (pixel->opacity == OpaqueOpacity))
+    {
+      alpha_pixel->red=(MagickRealType) pixel->red;
+      alpha_pixel->green=(MagickRealType) pixel->green;
+      alpha_pixel->blue=(MagickRealType) pixel->blue;
+      alpha_pixel->opacity=(MagickRealType) pixel->opacity;
+      return;
+    }
+  alpha=(MagickRealType) (QuantumScale*(QuantumRange-pixel->opacity));
+  alpha_pixel->red=alpha*pixel->red;
+  alpha_pixel->green=alpha*pixel->green;
+  alpha_pixel->blue=alpha*pixel->blue;
+  alpha_pixel->opacity=(MagickRealType) pixel->opacity;
+}
+
+static inline Quantum ClipToQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= QuantumRange)
+    return((Quantum) QuantumRange);
+  return((Quantum) (value+0.5));
+}
+
+static inline unsigned long ColorToNodeId(const CubeInfo *cube_info,
+  const RealPixelPacket *pixel,unsigned long index)
+{
+  unsigned long
+    id;
+
+  id=(unsigned long) (
+    ((ScaleQuantumToChar(ClipToQuantum(pixel->red)) >> index) & 0x1) |
+    ((ScaleQuantumToChar(ClipToQuantum(pixel->green)) >> index) & 0x1) << 1 |
+    ((ScaleQuantumToChar(ClipToQuantum(pixel->blue)) >> index) & 0x1) << 2);
+  if (cube_info->associate_alpha != MagickFalse)
+    id|=((ScaleQuantumToChar(ClipToQuantum(pixel->opacity)) >> index) & 0x1)
+      << 3;
+  return(id);
+}
+
+static inline MagickBooleanType IsSameColor(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  if ((p->red != q->red) || (p->green != q->green) || (p->blue != q->blue))
+    return(MagickFalse);
+  if ((image->matte != MagickFalse) && (p->opacity != q->opacity))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
+{
+#define AssignImageTag  "Assign/Image"
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  RealPixelPacket
+    pixel;
+
+  register long
+    i,
+    x;
+
+  register const NodeInfo
+    *node_info;
+
+  ssize_t
+    count;
+
+  unsigned long
+    id,
+    index;
+
+  /*
+    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
+    {
+      ExceptionInfo
+        *exception;
+
+      CacheView
+        *image_view;
+
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+      for (y=0; y < (long) image->rows; y++)
+      {
+        register IndexPacket
+          *__restrict indexes;
+
+        register PixelPacket
+          *__restrict q;
+
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          break;
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        for (x=0; x < (long) image->columns; x+=count)
+        {
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          for (count=1; (x+count) < (long) image->columns; count++)
+            if (IsSameColor(image,q,q+count) == MagickFalse)
+              break;
+          AssociateAlphaPixel(cube_info,q,&pixel);
+          node_info=cube_info->root;
+          for (index=MaxTreeDepth-1; (long) index > 0; index--)
+          {
+            id=ColorToNodeId(cube_info,&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_info->target=pixel;
+          cube_info->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
+            (QuantumRange+1.0)+1.0);
+          ClosestColor(image,cube_info,node_info->parent);
+          index=cube_info->color_number;
+          for (i=0; i < (long) count; i++)
+          {
+            if (image->storage_class == PseudoClass)
+              indexes[x+i]=(IndexPacket) index;
+            if (cube_info->quantize_info->measure_error == MagickFalse)
+              {
+                q->red=image->colormap[index].red;
+                q->green=image->colormap[index].green;
+                q->blue=image->colormap[index].blue;
+                if (cube_info->associate_alpha != MagickFalse)
+                  q->opacity=image->colormap[index].opacity;
+              }
+            q++;
+          }
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          break;
+        proceed=SetImageProgress(image,AssignImageTag,y,image->rows);
+        if (proceed == MagickFalse)
+          break;
+      }
+      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;
+
+      /*
+        Monochrome image.
+      */
+      q=image->colormap;
+      for (i=0; i < (long) image->colors; i++)
+      {
+        intensity=(Quantum) (PixelIntensity(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"
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  MagickRealType
+    bisect;
+
+  NodeInfo
+    *node_info;
+
+  RealPixelPacket
+    error,
+    mid,
+    midpoint,
+    pixel;
+
+  size_t
+    count;
+
+  unsigned long
+    id,
+    index,
+    level;
+
+  CacheView
+    *image_view;
+
+  /*
+    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.opacity=(MagickRealType) QuantumRange/2.0;
+  error.opacity=0.0;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) 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 < (long) image->columns; x+=(long) count)
+    {
+      /*
+        Start at the root and descend the color cube tree.
+      */
+      for (count=1; (x+count) < image->columns; count++)
+        if (IsSameColor(image,p,p+count) == MagickFalse)
+          break;
+      AssociateAlphaPixel(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.opacity+=(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.opacity=QuantumScale*(pixel.opacity-mid.opacity);
+        node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
+          count*error.green*error.green+count*error.blue*error.blue+
+          count*error.opacity*error.opacity));
+        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.opacity+=count*QuantumScale*pixel.opacity;
+      p+=count;
+    }
+    if (cube_info->colors > cube_info->maximum_colors)
+      {
+        PruneToCubeDepth(image,cube_info,cube_info->root);
+        break;
+      }
+    proceed=SetImageProgress(image,ClassifyImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  for (y++; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) 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 < (long) image->columns; x+=(long) count)
+    {
+      /*
+        Start at the root and descend the color cube tree.
+      */
+      for (count=1; (x+count) < image->columns; count++)
+        if (IsSameColor(image,p,p+count) == MagickFalse)
+          break;
+      AssociateAlphaPixel(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.opacity+=(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.opacity=QuantumScale*(pixel.opacity-mid.opacity);
+        node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
+          count*error.green*error.green+error.blue*error.blue+
+          count*error.opacity*error.opacity));
+        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.opacity+=count*QuantumScale*pixel.opacity;
+      p+=count;
+    }
+    proceed=SetImageProgress(image,ClassifyImageTag,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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) 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*(QuantumRange-p->opacity));
+          beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
+        }
+      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:
+%
+%      unsigned long 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 unsigned long DefineImageColormap(Image *image,CubeInfo *cube_info,
+  NodeInfo *node_info)
+{
+  register long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      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=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+            node_info->total_color.red));
+          q->green=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+            node_info->total_color.green));
+          q->blue=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+            node_info->total_color.blue));
+          q->opacity=OpaqueOpacity;
+        }
+      else
+        {
+          MagickRealType
+            opacity;
+
+          opacity=(MagickRealType) (alpha*QuantumRange*
+            node_info->total_color.opacity);
+          q->opacity=RoundToQuantum(opacity);
+          if (q->opacity == OpaqueOpacity)
+            {
+              q->red=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+                node_info->total_color.red));
+              q->green=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+                node_info->total_color.green));
+              q->blue=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
+                node_info->total_color.blue));
+            }
+          else
+            {
+              MagickRealType
+                gamma;
+
+              gamma=(MagickRealType) (QuantumScale*(QuantumRange-
+                (MagickRealType) q->opacity));
+              gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+              q->red=RoundToQuantum((MagickRealType) (alpha*gamma*QuantumRange*
+                node_info->total_color.red));
+              q->green=RoundToQuantum((MagickRealType) (alpha*gamma*
+                QuantumRange*node_info->total_color.green));
+              q->blue=RoundToQuantum((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=(long) 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 != (long *) NULL)
+    cube_info->cache=(long *) 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 MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info)
+{
+#define DitherImageTag  "Dither/Image"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    u,
+    v,
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  RealPixelPacket
+    color,
+    *current,
+    pixel,
+    *previous,
+    *scanlines;
+
+  register CubeInfo
+    *p;
+
+  unsigned long
+    index;
+
+  CacheView
+    *image_view;
+
+  /*
+    Distribute quantization error using Floyd-Steinberg.
+  */
+  scanlines=(RealPixelPacket *) AcquireQuantumMemory(image->columns,
+    2*sizeof(*scanlines));
+  if (scanlines == (RealPixelPacket *) NULL)
+    return(MagickFalse);
+  p=cube_info;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      i,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      return(MagickFalse);
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    current=scanlines+(y & 0x01)*image->columns;
+    previous=scanlines+((y+1) & 0x01)*image->columns;
+    v=(y & 0x01) ? -1 : 1;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      u=(y & 0x01) ? (long) image->columns-1-x : x;
+      AssociateAlphaPixel(cube_info,q+u,&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_info->associate_alpha != MagickFalse)
+            pixel.opacity+=7*current[u-v].opacity/16;
+        }
+      if (y > 0)
+        {
+          if (x < (long) (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_info->associate_alpha != MagickFalse)
+                pixel.opacity+=previous[u+v].opacity/16;
+            }
+          pixel.red+=5*previous[u].red/16;
+          pixel.green+=5*previous[u].green/16;
+          pixel.blue+=5*previous[u].blue/16;
+          if (cube_info->associate_alpha != MagickFalse)
+            pixel.opacity+=5*previous[u].opacity/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_info->associate_alpha != MagickFalse)
+                pixel.opacity+=3*previous[u-v].opacity/16;
+            }
+        }
+      pixel.red=(MagickRealType) ClipToQuantum(pixel.red);
+      pixel.green=(MagickRealType) ClipToQuantum(pixel.green);
+      pixel.blue=(MagickRealType) ClipToQuantum(pixel.blue);
+      if (cube_info->associate_alpha != MagickFalse)
+        pixel.opacity=(MagickRealType) ClipToQuantum(pixel.opacity);
+      i=(long) ((ScaleQuantumToChar(ClipToQuantum(pixel.red)) >> CacheShift) |
+        (ScaleQuantumToChar(ClipToQuantum(pixel.green)) >> CacheShift) << 6 |
+        (ScaleQuantumToChar(ClipToQuantum(pixel.blue)) >> CacheShift) << 12);
+      if (cube_info->associate_alpha != MagickFalse)
+        i|=((ScaleQuantumToChar(ClipToQuantum(pixel.opacity)) >> CacheShift)
+          << 18);
+      if (p->cache[i] < 0)
+        {
+          register NodeInfo
+            *node_info;
+
+          register unsigned long
+            id;
+
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          node_info=p->root;
+          for (index=MaxTreeDepth-1; (long) index > 0; index--)
+          {
+            id=ColorToNodeId(cube_info,&pixel,index);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              break;
+            node_info=node_info->child[id];
+          }
+          /*
+            Find closest color among siblings and their children.
+          */
+          p->target=pixel;
+          p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
+            1.0)+1.0);
+          ClosestColor(image,p,node_info->parent);
+          p->cache[i]=(long) p->color_number;
+        }
+      /*
+        Assign pixel to closest colormap entry.
+      */
+      index=(unsigned long) p->cache[i];
+      if (image->storage_class == PseudoClass)
+        indexes[u]=(IndexPacket) index;
+      if (cube_info->quantize_info->measure_error == MagickFalse)
+        {
+          (q+u)->red=image->colormap[index].red;
+          (q+u)->green=image->colormap[index].green;
+          (q+u)->blue=image->colormap[index].blue;
+          if (cube_info->associate_alpha != MagickFalse)
+            (q+u)->opacity=image->colormap[index].opacity;
+        }
+      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+        return(MagickFalse);
+      /*
+        Store the error.
+      */
+      AssociateAlphaPixel(cube_info,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_info->associate_alpha != MagickFalse)
+        current[u].opacity=pixel.opacity-color.opacity;
+      proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
+      if (proceed == MagickFalse)
+        return(MagickFalse);
+      p->offset++;
+    }
+  }
+  scanlines=(RealPixelPacket *) RelinquishMagickMemory(scanlines);
+  image_view=DestroyCacheView(image_view);
+  return(MagickTrue);
+}
+
+static MagickBooleanType
+  RiemersmaDither(Image *,CacheView *,CubeInfo *,const unsigned int);
+
+static void Riemersma(Image *image,CacheView *image_view,CubeInfo *cube_info,
+  const unsigned long 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;
+
+  unsigned long
+    index;
+
+  p=cube_info;
+  if ((p->x >= 0) && (p->x < (long) image->columns) &&
+      (p->y >= 0) && (p->y < (long) image->rows))
+    {
+      ExceptionInfo
+        *exception;
+
+      register IndexPacket
+        *__restrict indexes;
+
+      register long
+        i;
+
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Distribute error.
+      */
+      exception=(&image->exception);
+      q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
+      if (q == (PixelPacket *) NULL)
+        return(MagickFalse);
+      indexes=GetCacheViewAuthenticIndexQueue(image_view);
+      AssociateAlphaPixel(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.opacity+=p->weights[i]*p->error[i].opacity;
+      }
+      pixel.red=(MagickRealType) ClipToQuantum(pixel.red);
+      pixel.green=(MagickRealType) ClipToQuantum(pixel.green);
+      pixel.blue=(MagickRealType) ClipToQuantum(pixel.blue);
+      if (cube_info->associate_alpha != MagickFalse)
+        pixel.opacity=(MagickRealType) ClipToQuantum(pixel.opacity);
+      i=(long) ((ScaleQuantumToChar(ClipToQuantum(pixel.red)) >> CacheShift) |
+        (ScaleQuantumToChar(ClipToQuantum(pixel.green)) >> CacheShift) << 6 |
+        (ScaleQuantumToChar(ClipToQuantum(pixel.blue)) >> CacheShift) << 12);
+      if (cube_info->associate_alpha != MagickFalse)
+        i|=((ScaleQuantumToChar(ClipToQuantum(pixel.opacity)) >> CacheShift)
+          << 18);
+      if (p->cache[i] < 0)
+        {
+          register NodeInfo
+            *node_info;
+
+          register unsigned long
+            id;
+
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          node_info=p->root;
+          for (index=MaxTreeDepth-1; (long) index > 0; index--)
+          {
+            id=ColorToNodeId(cube_info,&pixel,index);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              break;
+            node_info=node_info->child[id];
+          }
+          /*
+            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]=(long) p->color_number;
+        }
+      /*
+        Assign pixel to closest colormap entry.
+      */
+      index=(unsigned long) (1*p->cache[i]);
+      if (image->storage_class == PseudoClass)
+        *indexes=(IndexPacket) index;
+      if (cube_info->quantize_info->measure_error == MagickFalse)
+        {
+          q->red=image->colormap[index].red;
+          q->green=image->colormap[index].green;
+          q->blue=image->colormap[index].blue;
+          if (cube_info->associate_alpha != MagickFalse)
+            q->opacity=image->colormap[index].opacity;
+        }
+      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]));
+      AssociateAlphaPixel(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].opacity=pixel.opacity-color.opacity;
+      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 long MagickMax(const long x,const long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline long MagickMin(const long x,const long y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
+{
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  unsigned long
+    depth;
+
+  CacheView
+    *image_view;
+
+  if (cube_info->quantize_info->dither_method == FloydSteinbergDitherMethod)
+    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((long) image->columns,(long) image->rows);
+  for (depth=1; i != 0; depth++)
+    i>>=1;
+  if ((long) (1L << depth) < MagickMax((long) image->columns,(long) 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 unsigned long depth,const unsigned long 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 unsigned long depth,const unsigned long maximum_colors)
+{
+  CubeInfo
+    *cube_info;
+
+  MagickRealType
+    sum,
+    weight;
+
+  size_t
+    length;
+
+  register long
+    i;
+
+  /*
+    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=(long *) AcquireQuantumMemory(length,
+    sizeof(*cube_info->cache));
+  if (cube_info->cache == (long *) NULL)
+    return((CubeInfo *) NULL);
+  /*
+    Initialize color cache.
+  */
+  for (i=0; i < (long) 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 unsigned long id,
+%        const unsigned long 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 unsigned long id,
+  const unsigned long 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)
+{
+  ExceptionInfo
+    *exception;
+
+  IndexPacket
+    *indexes;
+
+  long
+    y;
+
+  MagickRealType
+    alpha,
+    area,
+    beta,
+    distance,
+    maximum_error,
+    mean_error,
+    mean_error_per_pixel;
+
+  unsigned long
+    index;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      index=1UL*indexes[x];
+      if (image->matte != MagickFalse)
+        {
+          alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
+          beta=(MagickRealType) (QuantumScale*(QuantumRange-
+            image->colormap[index].opacity));
+        }
+      distance=fabs(alpha*p->red-beta*image->colormap[index].red);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      distance=fabs(alpha*p->green-beta*image->colormap[index].green);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      distance=fabs(alpha*p->blue-beta*image->colormap[index].blue);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      p++;
+    }
+  }
+  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                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  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 unsigned long 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.
+%
+*/
+MagickExport MagickBooleanType PosterizeImage(Image *image,
+  const unsigned long levels,const MagickBooleanType dither)
+{
+  ExceptionInfo
+    *exception;
+
+  Image
+    *posterize_image;
+
+  IndexPacket
+    *indexes;
+
+  long
+    j,
+    k,
+    l,
+    n;
+
+  MagickBooleanType
+    status;
+
+  QuantizeInfo
+    *quantize_info;
+
+  register long
+    i;
+
+  register PixelPacket
+    *__restrict q;
+
+  CacheView
+    *posterize_view;
+
+  /*
+    Posterize image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  posterize_image=AcquireImage((ImageInfo *) NULL);
+  if (posterize_image == (Image *) NULL)
+    return(MagickFalse);
+  l=1;
+  while ((l*l*l) < (long) MagickMin((long) levels*levels*levels,MaxColormapSize+1))
+    l++;
+  status=SetImageExtent(posterize_image,(unsigned long) (l*l*l),1);
+  if (status == MagickFalse)
+    {
+      posterize_image=DestroyImage(posterize_image);
+      return(MagickFalse);
+    }
+  status=AcquireImageColormap(posterize_image,levels*levels*levels);
+  if (status == MagickFalse)
+    {
+      posterize_image=DestroyImage(posterize_image);
+      return(MagickFalse);
+    }
+  posterize_view=AcquireCacheView(posterize_image);
+  exception=(&image->exception);
+  q=QueueCacheViewAuthenticPixels(posterize_view,0,0,posterize_image->columns,1,
+    exception);
+  if (q == (PixelPacket *) NULL)
+    {
+      posterize_view=DestroyCacheView(posterize_view);
+      posterize_image=DestroyImage(posterize_image);
+      return(MagickFalse);
+    }
+  indexes=GetCacheViewAuthenticIndexQueue(posterize_view);
+  n=0;
+  for (i=0; i < l; i++)
+    for (j=0; j < l; j++)
+      for (k=0; k < l; k++)
+      {
+        posterize_image->colormap[n].red=(Quantum) (QuantumRange*i/
+          MagickMax(l-1L,1L));
+        posterize_image->colormap[n].green=(Quantum)
+          (QuantumRange*j/MagickMax(l-1L,1L));
+        posterize_image->colormap[n].blue=(Quantum) (QuantumRange*k/
+          MagickMax(l-1L,1L));
+        posterize_image->colormap[n].opacity=OpaqueOpacity;
+        *q++=posterize_image->colormap[n];
+        indexes[n]=(IndexPacket) n;
+        n++;
+      }
+  if (SyncCacheViewAuthenticPixels(posterize_view,exception) == MagickFalse)
+    {
+      posterize_view=DestroyCacheView(posterize_view);
+      posterize_image=DestroyImage(posterize_image);
+      return(MagickFalse);
+    }
+  posterize_view=DestroyCacheView(posterize_view);
+  quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
+  quantize_info->dither=dither;
+  status=RemapImage(quantize_info,image,posterize_image);
+  quantize_info=DestroyQuantizeInfo(quantize_info);
+  posterize_image=DestroyImage(posterize_image);
+  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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) 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.opacity+=node_info->total_color.opacity;
+  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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) 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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) 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;
+
+  unsigned long
+    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 ((IsGrayImage(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)
+    {
+      unsigned long
+        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 long
+    i;
+
+  unsigned long
+    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)
+    {
+      unsigned long
+        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,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,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 long
+    i;
+
+  unsigned long
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (long) 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;
+
+  unsigned long
+    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)
+{
+  long
+    intensity;
+
+  PixelPacket
+    *color_1,
+    *color_2;
+
+  color_1=(PixelPacket *) x;
+  color_2=(PixelPacket *) y;
+  intensity=PixelIntensityToQuantum(color_1)-(long)
+    PixelIntensityToQuantum(color_2);
+  return(intensity);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static MagickBooleanType SetGrayscaleImage(Image *image)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    j,
+    y;
+
+  PixelPacket
+    *colormap;
+
+  long
+    *colormap_index;
+
+  register long
+    i;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->type != GrayscaleType)
+    (void) TransformImageColorspace(image,GRAYColorspace);
+  colormap_index=(long *) AcquireQuantumMemory(MaxMap+1,
+    sizeof(*colormap_index));
+  if (colormap_index == (long *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  if (image->storage_class != PseudoClass)
+    {
+      ExceptionInfo
+        *exception;
+
+      for (i=0; i <= (long) 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 < (long) image->rows; y++)
+      {
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          x;
+
+        register const PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        for (x=0; x < (long) image->columns; x++)
+        {
+          register unsigned long
+            intensity;
+
+          intensity=ScaleQuantumToMap(q->red);
+          if (colormap_index[intensity] < 0)
+            {
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+    #pragma omp critical (MagickCore_SetGrayscaleImage)
+#endif
+              if (colormap_index[intensity] < 0)
+                {
+                  colormap_index[intensity]=(long) image->colors;
+                  image->colormap[image->colors]=(*q);
+                  image->colors++;
+               }
+            }
+          indexes[x]=(IndexPacket) colormap_index[intensity];
+          q++;
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+    }
+  for (i=0; i < (long) image->colors; i++)
+    image->colormap[i].opacity=(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 < (long) image->colors; i++)
+  {
+    if (IsSameColor(image,&colormap[j],&image->colormap[i]) == MagickFalse)
+      {
+        j++;
+        colormap[j]=image->colormap[i];
+      }
+    colormap_index[(long) image->colormap[i].opacity]=j;
+  }
+  image->colors=(unsigned long) (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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register const PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+      indexes[x]=(IndexPacket) colormap_index[ScaleQuantumToMap(indexes[x])];
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  colormap_index=(long *) RelinquishMagickMemory(colormap_index);
+  image->type=GrayscaleType;
+  if (IsMonochromeImage(image,&image->exception) != MagickFalse)
+    image->type=BilevelType;
+  return(status);
+}
diff --git a/magick/quantize.h b/magick/quantize.h
new file mode 100644
index 0000000..6f6ca54
--- /dev/null
+++ b/magick/quantize.h
@@ -0,0 +1,80 @@
+/*
+  Copyright 1999-2009 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 "magick/colorspace.h"
+
+typedef enum
+{
+  UndefinedDitherMethod,
+  NoDitherMethod,
+  RiemersmaDitherMethod,
+  FloydSteinbergDitherMethod
+} DitherMethod;
+
+typedef struct _QuantizeInfo
+{
+  unsigned long
+    number_colors;
+
+  unsigned long
+    tree_depth;
+
+  MagickBooleanType
+    dither;
+
+  ColorspaceType
+    colorspace;
+
+  MagickBooleanType
+    measure_error;
+
+  unsigned long
+    signature;
+
+  DitherMethod
+    dither_method;
+} QuantizeInfo;
+
+extern MagickExport MagickBooleanType
+  CompressImageColormap(Image *),
+  GetImageQuantizeError(Image *),
+  PosterizeImage(Image *,const unsigned long,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/magick/quantum-export.c b/magick/quantum-export.c
new file mode 100644
index 0000000..c3b9d18
--- /dev/null
+++ b/magick/quantum-export.c
@@ -0,0 +1,2360 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/color-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/cache.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/statistic.h"
+#include "magick/stream.h"
+#include "magick/string_.h"
+#include "magick/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 unsigned long depth,const QuantumAny pixel,unsigned char *pixels)
+{
+  register long
+    i;
+
+  register unsigned long
+    quantum_bits;
+
+  if (quantum_state->bits == 0UL)
+    quantum_state->bits=8UL;
+  for (i=(long) depth; i > 0L; )
+  {
+    quantum_bits=(unsigned long) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    i-=quantum_bits;
+    if (quantum_state->bits == 8)
+      *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 unsigned long depth,const unsigned long pixel,unsigned char *pixels)
+{
+  register long
+    i;
+
+  unsigned long
+    quantum_bits;
+
+  if (quantum_state->bits == 0UL)
+    quantum_state->bits=32UL;
+  for (i=(long) depth; i > 0; )
+  {
+    quantum_bits=(unsigned long) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    quantum_state->pixel|=(((pixel >> (depth-i)) &
+      quantum_state->mask[quantum_bits]) << (32UL-quantum_state->bits));
+    i-=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=32UL;
+      }
+  }
+  return(pixels);
+}
+
+MagickExport size_t ExportQuantumPixels(const Image *image,
+  const CacheView *image_view,const QuantumInfo *quantum_info,
+  const QuantumType quantum_type,unsigned char *pixels,ExceptionInfo *exception)
+{
+  EndianType
+    endian;
+
+  long
+    bit;
+
+  MagickRealType
+    alpha;
+
+  MagickSizeType
+    number_pixels;
+
+  QuantumAny
+    range;
+
+  QuantumState
+    quantum_state;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    x;
+
+  register unsigned char
+    *q;
+
+  size_t
+    extent;
+
+  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);
+  number_pixels=GetImageExtent(image);
+  p=GetVirtualPixelQueue(image);
+  indexes=GetVirtualIndexQueue(image);
+  if (image_view != (CacheView *) NULL)
+    {
+      number_pixels=GetCacheViewExtent(image_view);
+      p=GetCacheViewVirtualPixelQueue(image_view);
+      indexes=GetCacheViewVirtualIndexQueue(image_view);
+    }
+  if (quantum_info->alpha_type == AssociatedQuantumAlpha)
+    {
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Associate alpha.
+      */
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=(PixelPacket *) GetCacheViewVirtualPixelQueue(image_view);
+      for (x=0; x < (long) image->columns; x++)
+      {
+        alpha=QuantumScale*((double) QuantumRange-q->opacity);
+        q->red=RoundToQuantum(alpha*q->red);
+        q->green=RoundToQuantum(alpha*q->green);
+        q->blue=RoundToQuantum(alpha*q->blue);
+        q++;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum))
+    {
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=(PixelPacket *) GetCacheViewVirtualPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        q->opacity=(Quantum) (QuantumRange-q->opacity);
+        q++;
+      }
+    }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetAuthenticPixelQueue(image);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        quantum=q->red;
+        q->red=q->green;
+        q->green=quantum;
+        q++;
+      }
+    }
+  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=((long) number_pixels-7); x > 0; x-=8)
+          {
+            pixel=(unsigned char) *indexes++;
+            *q=((pixel & 0x01) << 7);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 6);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 5);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 4);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 3);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 2);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 1);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 0);
+            q++;
+          }
+          if ((number_pixels % 8) != 0)
+            {
+              *q='\0';
+              for (bit=7; bit >= (long) (8-(number_pixels % 8)); bit--)
+              {
+                pixel=(unsigned char) *indexes++;
+                *q|=((pixel & 0x01) << (unsigned char) bit);
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) (number_pixels-1) ; x+=2)
+          {
+            pixel=(unsigned char) *indexes++;
+            *q=((pixel & 0xf) << 4);
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0xf) << 0);
+            q++;
+          }
+          if ((number_pixels % 2) != 0)
+            {
+              pixel=(unsigned char) *indexes++;
+              *q=((pixel & 0xf) << 4);
+              q++;
+            }
+          break;
+        }
+        case 8:
+        {
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopCharPixel((unsigned char) indexes[x],q);
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopShortPixel(endian,(unsigned short) indexes[x],q);
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopLongPixel(endian,(unsigned long) indexes[x],q);
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,indexes[x],q);
+            p++;
+            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=((long) number_pixels-3); x > 0; x-=4)
+          {
+            pixel=(unsigned char) *indexes++;
+            *q=((pixel & 0x01) << 7);
+            pixel=(unsigned char) (p->opacity == (Quantum) TransparentOpacity ?
+              1 : 0);
+            *q|=((pixel & 0x01) << 6);
+            p++;
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 5);
+            pixel=(unsigned char) (p->opacity == (Quantum) TransparentOpacity ?
+              1 : 0);
+            *q|=((pixel & 0x01) << 4);
+            p++;
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 3);
+            pixel=(unsigned char) (p->opacity == (Quantum) TransparentOpacity ?
+              1 : 0);
+            *q|=((pixel & 0x01) << 2);
+            p++;
+            pixel=(unsigned char) *indexes++;
+            *q|=((pixel & 0x01) << 1);
+            pixel=(unsigned char) (p->opacity == (Quantum) TransparentOpacity ?
+              1 : 0);
+            *q|=((pixel & 0x01) << 0);
+            p++;
+            q++;
+          }
+          if ((number_pixels % 4) != 0)
+            {
+              *q='\0';
+              for (bit=3; bit >= (long) (4-(number_pixels % 4)); bit-=2)
+              {
+                pixel=(unsigned char) *indexes++;
+                *q|=((pixel & 0x01) << (unsigned char) bit);
+                pixel=(unsigned char) (p->opacity == (Quantum)
+                  TransparentOpacity ? 1 : 0);
+                *q|=((pixel & 0x01) << (unsigned char) (bit-1));
+                p++;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels ; x++)
+          {
+            pixel=(unsigned char) *indexes++;
+            *q=((pixel & 0xf) << 4);
+            pixel=(unsigned char) (16*QuantumScale*((Quantum) (QuantumRange-
+              p->opacity))+0.5);
+            *q|=((pixel & 0xf) << 0);
+            p++;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopCharPixel((unsigned char) indexes[x],q);
+            pixel=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopShortPixel(endian,(unsigned short) indexes[x],q);
+            pixel=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float) indexes[x],q);
+                pixel=(float)  (QuantumRange-p->opacity);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopLongPixel(endian,(unsigned long) indexes[x],q);
+            pixel=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                q=PopDoublePixel(&quantum_state,(double) indexes[x],q);
+                pixel=(double) (QuantumRange-p->opacity);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,indexes[x],q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              (Quantum) (QuantumRange-p->opacity),range),q);
+            p++;
+            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=((long) number_pixels-7); x > 0; x-=8)
+          {
+            *q='\0';
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 7;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 6;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 5;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 4;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 3;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 2;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 1;
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 0;
+            p++;
+            q++;
+          }
+          if ((number_pixels % 8) != 0)
+            {
+              *q='\0';
+              for (bit=7; bit >= (long) (8-(number_pixels % 8)); bit--)
+              {
+                *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) <<
+                  bit;
+                p++;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) (number_pixels-1) ; x+=2)
+          {
+            pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            *q=(((pixel >> 4) & 0xf) << 4);
+            p++;
+            pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            *q|=pixel >> 4;
+            p++;
+            q++;
+          }
+          if ((number_pixels % 2) != 0)
+            {
+              pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+              *q=(((pixel >> 4) & 0xf) << 4);
+              p++;
+              q++;
+            }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned short
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                pixel=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+                q=PopShortPixel(endian,(unsigned short) ScaleQuantumToAny(
+                  (Quantum) pixel,range),q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              PixelIntensityToQuantum(p),range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 12:
+        {
+          register unsigned short
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                pixel=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+                q=PopShortPixel(endian,(unsigned short) (pixel >> 4),q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              PixelIntensityToQuantum(p),range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) PixelIntensityToQuantum(p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(PixelIntensityToQuantum(p));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) PixelIntensityToQuantum(p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              PixelIntensityToQuantum(p),range),q);
+            p++;
+            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=((long) number_pixels-3); x > 0; x-=4)
+          {
+            *q='\0';
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 7;
+            pixel=(unsigned char) (p->opacity == OpaqueOpacity ? 0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 6);
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 5;
+            pixel=(unsigned char) (p->opacity == OpaqueOpacity ? 0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 4);
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 3;
+            pixel=(unsigned char) (p->opacity == OpaqueOpacity ? 0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 2);
+            p++;
+            *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) << 1;
+            pixel=(unsigned char) (p->opacity == OpaqueOpacity ? 0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 0);
+            p++;
+            q++;
+          }
+          if ((number_pixels % 4) != 0)
+            {
+              *q='\0';
+              for (bit=3; bit >= (long) (4-(number_pixels % 4)); bit-=2)
+              {
+                *q|=(PixelIntensityToQuantum(p) < threshold ? black : white) <<
+                  bit;
+                pixel=(unsigned char) (p->opacity == OpaqueOpacity ? 0x00 :
+                  0x01);
+                *q|=(((int) pixel != 0 ? 0x00 : 0x01) << (unsigned char)
+                  (bit-1));
+                p++;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels ; x++)
+          {
+            pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            *q=(((pixel >> 4) & 0xf) << 4);
+            pixel=(unsigned char) (16*QuantumScale*((Quantum) (QuantumRange-
+              p->opacity))+0.5);
+            *q|=pixel & 0xf;
+            p++;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) PixelIntensityToQuantum(p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                pixel=(float) (QuantumRange-p->opacity);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(PixelIntensityToQuantum(p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) PixelIntensityToQuantum(p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                pixel=(double) (QuantumRange-p->opacity);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              PixelIntensityToQuantum(p),range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              (Quantum) (QuantumRange-p->opacity),range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RedQuantum:
+    case CyanQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->red);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->red);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->red,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->red);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->red,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->red,range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GreenQuantum:
+    case MagentaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->green);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->green);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->green,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->green);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->green,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->green,range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlueQuantum:
+    case YellowQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->blue);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->blue);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->blue,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->blue);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->blue,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->blue,range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case AlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) (QuantumRange-p->opacity);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) (QuantumRange-p->opacity);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              (Quantum) (QuantumRange-p->opacity),range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case OpacityQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->opacity);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->opacity);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->opacity,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->opacity);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->opacity,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->opacity,range),q);
+            p++;
+            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 < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(indexes[x]);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(indexes[x]);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(indexes[x]);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              (Quantum) indexes[x],range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBQuantum:
+    case CbYCrQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopCharPixel(ScaleQuantumToChar(p->red),q);
+            q=PopCharPixel(ScaleQuantumToChar(p->green),q);
+            q=PopCharPixel(ScaleQuantumToChar(p->blue),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned long
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                pixel=(unsigned long) (ScaleQuantumToAny(p->red,range) << 22 |
+                  ScaleQuantumToAny(p->green,range) <<  12 |
+                  ScaleQuantumToAny(p->blue,range) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 12:
+        {
+          register unsigned long
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) (3*number_pixels-1); x+=2)
+              {
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+                    p++;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+                    p++;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              for (bit=0; bit < (long) (3*number_pixels % 2); bit++)
+              {
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+                    p++;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+                q=PopQuantumLongPixel(&quantum_state,image->depth,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=(unsigned long) ScaleQuantumToAny(p->red,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            pixel=(unsigned long) ScaleQuantumToAny(p->green,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            pixel=(unsigned long) ScaleQuantumToAny(p->blue,range);
+            q=PopQuantumPixel(&quantum_state,image->depth,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->red);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->green);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->blue);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->red,q);
+                q=PopFloatPixel(&quantum_state,(float) p->green,q);
+                q=PopFloatPixel(&quantum_state,(float) p->blue,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->red);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->green);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->blue);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->red,q);
+                q=PopDoublePixel(&quantum_state,(double) p->green,q);
+                q=PopDoublePixel(&quantum_state,(double) p->blue,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->red,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->green,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->blue,range),q);
+            p++;
+            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 < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->red);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->green);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->blue);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->red);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->green);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->blue);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float) p->red,q);
+                q=PopFloatPixel(&quantum_state,(float) p->green,q);
+                q=PopFloatPixel(&quantum_state,(float) p->blue,q);
+                pixel=(float) (QuantumRange-p->opacity);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->red);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->green);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->blue);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->red,q);
+                q=PopDoublePixel(&quantum_state,(double) p->green,q);
+                q=PopDoublePixel(&quantum_state,(double) p->blue,q);
+                pixel=(double) (QuantumRange-p->opacity);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->red,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->green,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->blue,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              (Quantum) (QuantumRange-p->opacity),range),q);
+            p++;
+            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 < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->red);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->green);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->blue);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(indexes[x]);
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->red);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->green);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->blue);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(indexes[x]);
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float) p->red,q);
+                q=PopFloatPixel(&quantum_state,(float) p->green,q);
+                q=PopFloatPixel(&quantum_state,(float) p->blue,q);
+                q=PopFloatPixel(&quantum_state,(float) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->red);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->green);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->blue);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(indexes[x]);
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->red,q);
+                q=PopDoublePixel(&quantum_state,(double) p->green,q);
+                q=PopDoublePixel(&quantum_state,(double) p->blue,q);
+                q=PopDoublePixel(&quantum_state,(double) indexes[x],q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->red,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->green,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->blue,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              indexes[x],range),q);
+            p++;
+            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 < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(p->red);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->green);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(p->blue);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(indexes[x]);
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            q=PopCharPixel(pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(p->red);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->green);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(p->blue);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(indexes[x]);
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            q=PopShortPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float) p->red,q);
+                q=PopFloatPixel(&quantum_state,(float) p->green,q);
+                q=PopFloatPixel(&quantum_state,(float) p->blue,q);
+                q=PopFloatPixel(&quantum_state,(float) indexes[x],q);
+                pixel=(float) (QuantumRange-p->opacity);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(p->red);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->green);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(p->blue);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(indexes[x]);
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            q=PopLongPixel(endian,pixel,q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double) p->red,q);
+                q=PopDoublePixel(&quantum_state,(double) p->green,q);
+                q=PopDoublePixel(&quantum_state,(double) p->blue,q);
+                q=PopDoublePixel(&quantum_state,(double) indexes[x],q);
+                pixel=(double) (QuantumRange-p->opacity);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->red,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->green,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->blue,range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              indexes[x],range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              p->opacity,range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CbYCrYQuantum:
+    {
+     long
+        n;
+
+      Quantum
+        cbcr[4];
+
+      register long
+        i;
+
+      register unsigned long
+        pixel;
+
+      unsigned long
+        quantum;
+
+      n=0;
+      quantum=0;
+      range=GetQuantumRange(image->depth);
+      switch (quantum_info->depth)
+      {
+        case 10:
+        {
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x+=2)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      quantum=p->red;
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=p->green;
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=p->blue;
+                      break;
+                    }
+                  }
+                  cbcr[i]=(Quantum) quantum;
+                  n++;
+                }
+                pixel=(unsigned long) ((unsigned long) (cbcr[1]) << 22 |
+                  (unsigned long) (cbcr[0]) <<  12 |
+                  (unsigned long) (cbcr[2]) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p++;
+                pixel=(unsigned long) ((unsigned long) (cbcr[3]) << 22 |
+                  (unsigned long) (cbcr[0]) <<  12 |
+                  (unsigned long) (cbcr[2]) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p++;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          break;
+        }
+        default:
+        {
+          for (x=0; x < (long) number_pixels; x+=2)
+          {
+            for (i=0; i < 4; i++)
+            {
+              switch (n % 3)
+              {
+                case 0:
+                {
+                  quantum=p->red;
+                  break;
+                }
+                case 1:
+                {
+                  quantum=p->green;
+                  break;
+                }
+                case 2:
+                {
+                  quantum=p->blue;
+                  break;
+                }
+              }
+              cbcr[i]=(Quantum) quantum;
+              n++;
+            }
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[1],range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[0],range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[2],range),q);
+            p++;
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[3],range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[0],range),q);
+            q=PopQuantumPixel(&quantum_state,image->depth,ScaleQuantumToAny(
+              cbcr[2],range),q);
+            p++;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=(PixelPacket *) GetCacheViewVirtualPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        quantum=q->red;
+        q->red=q->green;
+        q->green=quantum;
+        q++;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum))
+    {
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=(PixelPacket *) GetCacheViewVirtualPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        q->opacity=(Quantum) (QuantumRange-q->opacity);
+        q++;
+      }
+    }
+  return(extent);
+}
diff --git a/magick/quantum-import.c b/magick/quantum-import.c
new file mode 100644
index 0000000..5293429
--- /dev/null
+++ b/magick/quantum-import.c
@@ -0,0 +1,2529 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/color-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/cache.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/statistic.h"
+#include "magick/stream.h"
+#include "magick/string_.h"
+#include "magick/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 IndexPacket PushColormapIndex(Image *image,
+  const unsigned long index,MagickBooleanType *range_exception)
+{
+  if (index < image->colors)
+    return((IndexPacket) index);
+  *range_exception=MagickTrue;
+  return((IndexPacket) 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 unsigned long depth,
+  const unsigned char *pixels,unsigned long *quantum)
+{
+  register long
+    i;
+
+  register unsigned long
+    quantum_bits;
+
+  *quantum=(QuantumAny) 0;
+  for (i=(long) depth; i > 0L; )
+  {
+    if (quantum_state->bits == 0UL)
+      {
+        quantum_state->pixel=(*pixels++);
+        quantum_state->bits=8UL;
+      }
+    quantum_bits=(unsigned long) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    i-=quantum_bits;
+    quantum_state->bits-=quantum_bits;
+    *quantum=(*quantum << quantum_bits) | ((quantum_state->pixel >>
+      quantum_state->bits) &~ ((~0UL) << quantum_bits));
+  }
+  return(pixels);
+}
+
+static inline const unsigned char *PushQuantumLongPixel(
+  QuantumState *quantum_state,const unsigned long depth,
+  const unsigned char *pixels,unsigned long *quantum)
+{
+  register long
+    i;
+
+  register unsigned long
+    quantum_bits;
+
+  *quantum=0UL;
+  for (i=(long) depth; i > 0; )
+  {
+    if (quantum_state->bits == 0)
+      {
+        pixels=PushLongPixel(quantum_state->endian,pixels,
+          &quantum_state->pixel);
+        quantum_state->bits=32UL;
+      }
+    quantum_bits=(unsigned long) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    *quantum|=(((quantum_state->pixel >> (32UL-quantum_state->bits)) &
+      quantum_state->mask[quantum_bits]) << (depth-i));
+    i-=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;
+
+  long
+    bit;
+
+  MagickSizeType
+    number_pixels;
+
+  QuantumAny
+    range;
+
+  QuantumState
+    quantum_state;
+
+  register const unsigned char
+    *p;
+
+  register IndexPacket
+    *indexes;
+
+  register long
+    x;
+
+  register PixelPacket
+    *__restrict q;
+
+  size_t
+    extent;
+
+  unsigned long
+    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;
+  number_pixels=GetImageExtent(image);
+  q=GetAuthenticPixelQueue(image);
+  indexes=GetAuthenticIndexQueue(image);
+  if (image_view != (CacheView *) NULL)
+    {
+      number_pixels=GetCacheViewExtent(image_view);
+      q=GetCacheViewAuthenticPixelQueue(image_view);
+      indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    }
+  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 < ((long) 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);
+              indexes[x+bit]=PushColormapIndex(image,pixel,&range_exception);
+              *q=image->colormap[(long) indexes[x+bit]];
+              q++;
+            }
+            p++;
+          }
+          for (bit=0; bit < (long) (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);
+            indexes[x+bit]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x+bit]];
+            q++;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((long) number_pixels-1); x+=2)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            q++;
+            pixel=(unsigned char) ((*p) & 0xf);
+            indexes[x+1]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x+1]];
+            p++;
+            q++;
+          }
+          for (bit=0; bit < (long) (number_pixels % 2); bit++)
+          {
+            pixel=(unsigned char) ((*p++ >> 4) & 0xf);
+            indexes[x+bit]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x+bit]];
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                indexes[x]=PushColormapIndex(image,RoundToQuantum(pixel),
+                  &range_exception);
+                *q=image->colormap[(long) indexes[x]];
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                indexes[x]=PushColormapIndex(image,RoundToQuantum(pixel),
+                  &range_exception);
+                *q=image->colormap[(long) indexes[x]];
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p+=quantum_info->pad;
+            q++;
+          }
+          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 < ((long) 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);
+              indexes[x+bit/2]=(IndexPacket) (pixel == 0 ? 0 : 1);
+              q->red=(Quantum) (pixel == 0 ? 0 : QuantumRange);
+              q->green=q->red;
+              q->blue=q->red;
+              q->opacity=(Quantum) (((*p) & (1UL << (unsigned char) (6-bit)))
+                == 0 ? TransparentOpacity : OpaqueOpacity);
+              q++;
+            }
+          }
+          for (bit=0; bit < (long) (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);
+            indexes[x+bit/2]=(IndexPacket) (pixel == 0 ? 0 : 1);
+            q->red=(Quantum) (pixel == 0 ? 0 : QuantumRange);
+            q->green=q->red;
+            q->blue=q->red;
+            q->opacity=(Quantum) (((*p) & (1UL << (unsigned char) (6-bit))) ==
+              0 ? TransparentOpacity : OpaqueOpacity);
+            q++;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            pixel=(unsigned char) ((*p) & 0xf);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            p++;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p=PushCharPixel(p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p=PushShortPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                indexes[x]=PushColormapIndex(image,RoundToQuantum(pixel),
+                  &range_exception);
+                *q=image->colormap[(long) indexes[x]];
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p=PushLongPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleLongToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                indexes[x]=PushColormapIndex(image,RoundToQuantum(pixel),
+                  &range_exception);
+                *q=image->colormap[(long) indexes[x]];
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            indexes[x]=PushColormapIndex(image,pixel,&range_exception);
+            *q=image->colormap[(long) indexes[x]];
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      if (range_exception != MagickFalse)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+      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 < ((long) number_pixels-7); x+=8)
+          {
+            for (bit=0; bit < 8; bit++)
+            {
+              q->red=(((*p) & (1 << (7-bit))) == 0 ? black : white);
+              q->green=q->red;
+              q->blue=q->red;
+              q++;
+            }
+            p++;
+          }
+          for (bit=0; bit < (long) (number_pixels % 8); bit++)
+          {
+            q->red=(((*p) & (1 << (7-bit))) == 0 ? black : white);
+            q->green=q->red;
+            q->blue=q->red;
+            q++;
+          }
+          if (bit != 0)
+            p++;
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < ((long) number_pixels-1); x+=2)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            q++;
+            pixel=(unsigned char) ((*p) & 0xf);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p++;
+            q++;
+          }
+          for (bit=0; bit < (long) (number_pixels % 2); bit++)
+          {
+            pixel=(unsigned char) (*p++ >> 4);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushCharPixel(p,&pixel);
+                q->red=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+                q->green=q->red;
+                q->blue=q->red;
+                q->opacity=OpaqueOpacity;
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            q->opacity=OpaqueOpacity;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              if (image->endian != LSBEndian)
+                {
+                  for (x=0; x < (long) number_pixels/3; x++)
+                  {
+                    p=PushLongPixel(endian,p,&pixel);
+                    q->red=ScaleAnyToQuantum((pixel >> 0) & 0x3ff,range);
+                    q->green=q->red;
+                    q->blue=q->red;
+                    q++;
+                    q->red=ScaleAnyToQuantum((pixel >> 10) & 0x3ff,range);
+                    q->green=q->red;
+                    q->blue=q->red;
+                    q++;
+                    q->red=ScaleAnyToQuantum((pixel >> 20) & 0x3ff,range);
+                    q->green=q->red;
+                    q->blue=q->red;
+                    p+=quantum_info->pad;
+                    q++;
+                  }
+                  break;
+                }
+              for (x=0; x < (long) number_pixels/3; x++)
+              {
+                p=PushLongPixel(endian,p,&pixel);
+                q->red=ScaleAnyToQuantum((pixel >> 22) & 0x3ff,range);
+                q->green=q->red;
+                q->blue=q->red;
+                q++;
+                q->red=ScaleAnyToQuantum((pixel >> 12) & 0x3ff,range);
+                q->green=q->red;
+                q->blue=q->red;
+                q++;
+                q->red=ScaleAnyToQuantum((pixel >> 2) & 0x3ff,range);
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              unsigned short
+                pixel;
+
+              for (x=0; x < (long) (number_pixels-1); x+=2)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                q->green=q->red;
+                q->blue=q->red;
+                q++;
+                p=PushShortPixel(endian,p,&pixel);
+                q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              for (bit=0; bit < (long) (number_pixels % 2); bit++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                q->red=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                q->green=q->red;
+                q->blue=q->red;
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GrayAlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((long) number_pixels-3); x+=4)
+          {
+            for (bit=0; bit < 8; bit+=2)
+            {
+              pixel=(unsigned char)
+                (((*p) & (1 << (7-bit))) != 0 ? 0x00 : 0x01);
+              q->red=(Quantum) (pixel == 0 ? 0 : QuantumRange);
+              q->green=q->red;
+              q->blue=q->red;
+              q->opacity=(Quantum) (((*p) & (1UL << (unsigned char) (6-bit)))
+                == 0 ? TransparentOpacity : OpaqueOpacity);
+              q++;
+            }
+            p++;
+          }
+          for (bit=0; bit < (long) (number_pixels % 4); bit+=2)
+          {
+            pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ? 0x00 : 0x01);
+            q->red=(Quantum) (pixel == 0 ? 0 : QuantumRange);
+            q->green=q->red;
+            q->blue=q->red;
+            q->opacity=(Quantum) (((*p) & (1UL << (unsigned char) (6-bit))) == 0
+              ? TransparentOpacity : OpaqueOpacity);
+            q++;
+          }
+          if (bit != 0)
+            p++;
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            pixel=(unsigned char) ((*p) & 0xf);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            p++;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushCharPixel(p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushShortPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                q->green=q->red;
+                q->blue=q->red;
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushLongPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleLongToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                q->green=q->red;
+                q->blue=q->red;
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            q->green=q->red;
+            q->blue=q->red;
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RedQuantum:
+    case CyanQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GreenQuantum:
+    case MagentaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->green=ScaleCharToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->green=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->green=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlueQuantum:
+    case YellowQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->blue=ScaleCharToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->blue=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->blue=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case AlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleLongToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            p+=quantum_info->pad;
+            q++;
+          }
+          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 < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            indexes[x]=ScaleCharToQuantum(pixel);
+            p+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            indexes[x]=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                indexes[x]=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            indexes[x]=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                indexes[x]=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            indexes[x]=ScaleAnyToQuantum(pixel,range);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBQuantum:
+    case CbYCrQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->green=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->blue=ScaleCharToQuantum(pixel);
+            q->opacity=OpaqueOpacity;
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushLongPixel(endian,p,&pixel);
+                q->red=ScaleAnyToQuantum((pixel >> 22) & 0x3ff,range);
+                q->green=ScaleAnyToQuantum((pixel >> 12) & 0x3ff,range);
+                q->blue=ScaleAnyToQuantum((pixel >> 2) & 0x3ff,range);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->red=ScaleAnyToQuantum(pixel,range);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->green=ScaleAnyToQuantum(pixel,range);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->blue=ScaleAnyToQuantum(pixel,range);
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            q++;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              unsigned short
+                pixel;
+
+              for (x=0; x < (long) (3*number_pixels-1); x+=2)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    q->green=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    q->blue=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    q++;
+                    break;
+                  }
+                }
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    q->green=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    q->blue=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    q++;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              for (bit=0; bit < (long) (3*number_pixels % 2); bit++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    q->red=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    q->green=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    q->blue=ScaleAnyToQuantum((QuantumAny) (pixel >> 4),range);
+                    q++;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->red=ScaleAnyToQuantum(pixel,range);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->green=ScaleAnyToQuantum(pixel,range);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                q->blue=ScaleAnyToQuantum(pixel,range);
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->green=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->blue=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->green=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->blue=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBAQuantum:
+    case RGBOQuantum:
+    case CbYCrAQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->green=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->blue=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 10:
+        {
+          pixel=0;
+          if (quantum_info->pack == MagickFalse)
+            {
+              long
+                n;
+
+              register long
+                i;
+
+              unsigned long
+                quantum;
+
+              n=0;
+              quantum=0;
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      p=PushLongPixel(endian,p,&pixel);
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 22) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 12) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 2) & 0x3ff) << 6)));
+                      break;
+                    }
+                  }
+                  switch (i)
+                  {
+                    case 0: q->red=(Quantum) (quantum); break;
+                    case 1: q->green=(Quantum) (quantum); break;
+                    case 2: q->blue=(Quantum) (quantum); break;
+                    case 3: q->opacity=(Quantum) (QuantumRange-quantum); break;
+                  }
+                  n++;
+                }
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleShortToQuantum((unsigned short) (pixel << 6));
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleShortToQuantum((unsigned short) (pixel << 6));
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleShortToQuantum((unsigned short) (pixel << 6));
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(
+              (unsigned short) (pixel << 6)));
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->green=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->blue=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->green=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->blue=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleLongToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            q++;
+          }
+          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 < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->green=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->blue=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            indexes[x]=ScaleCharToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->green=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->blue=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            indexes[x]=ScaleShortToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                indexes[x]=(IndexPacket) RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->green=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->blue=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            indexes[x]=ScaleLongToQuantum(pixel);
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                indexes[x]=(IndexPacket) RoundToQuantum(pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            indexes[x]=ScaleAnyToQuantum(pixel,range);
+            q++;
+          }
+          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 < (long) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            q->red=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->green=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->blue=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            indexes[x]=ScaleCharToQuantum(pixel);
+            p=PushCharPixel(p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            q->red=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->green=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->blue=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            indexes[x]=ScaleShortToQuantum(pixel);
+            p=PushShortPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleShortToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned long
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                indexes[x]=(IndexPacket) RoundToQuantum(pixel);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            q->red=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->green=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->blue=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            indexes[x]=ScaleLongToQuantum(pixel);
+            p=PushLongPixel(endian,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleLongToQuantum(pixel));
+            p+=quantum_info->pad;
+            q++;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (long) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->red=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->green=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->blue=RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                indexes[x]=(IndexPacket) RoundToQuantum(pixel);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                q->opacity=(Quantum) (QuantumRange-RoundToQuantum(pixel));
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                p+=quantum_info->pad;
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->blue=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            indexes[x]=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->opacity=(Quantum) (QuantumRange-ScaleAnyToQuantum(pixel,range));
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CbYCrYQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 10:
+        {
+          Quantum
+            cbcr[4];
+
+          pixel=0;
+          if (quantum_info->pack == MagickFalse)
+            {
+              long
+                n;
+
+              register long
+                i;
+
+              unsigned long
+                quantum;
+
+              n=0;
+              quantum=0;
+              for (x=0; x < (long) number_pixels; x+=2)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      p=PushLongPixel(endian,p,&pixel);
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 22) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 12) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=(unsigned long) (ScaleShortToQuantum(
+                        (unsigned short) (((pixel >> 2) & 0x3ff) << 6)));
+                      break;
+                    }
+                  }
+                  cbcr[i]=(Quantum) (quantum);
+                  n++;
+                }
+                p+=quantum_info->pad;
+                q->red=cbcr[1];
+                q->green=cbcr[0];
+                q->blue=cbcr[2];
+                q++;
+                q->red=cbcr[3];
+                q->green=cbcr[0];
+                q->blue=cbcr[2];
+                q++;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (long) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->red=ScaleAnyToQuantum(pixel,range);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            q->green=ScaleAnyToQuantum(pixel,range);
+            q++;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        quantum=q->red;
+        q->red=q->green;
+        q->green=quantum;
+        q++;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum))
+    {
+      register PixelPacket
+        *__restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        q->opacity=(Quantum) (QuantumRange-q->opacity);
+        q++;
+      }
+    }
+  if (quantum_info->alpha_type == DisassociatedQuantumAlpha)
+    {
+      MagickRealType
+        alpha;
+
+      register PixelPacket
+        *__restrict q;
+
+      /*
+        Disassociate alpha.
+      */
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (long) number_pixels; x++)
+      {
+        alpha=QuantumScale*((MagickRealType) QuantumRange-q->opacity);
+        alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        q->red=RoundToQuantum(alpha*q->red);
+        q->green=RoundToQuantum(alpha*q->green);
+        q->blue=RoundToQuantum(alpha*q->blue);
+        q++;
+      }
+    }
+  return(extent);
+}
diff --git a/magick/quantum-private.h b/magick/quantum-private.h
new file mode 100644
index 0000000..856d277
--- /dev/null
+++ b/magick/quantum-private.h
@@ -0,0 +1,531 @@
+/*
+  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 "magick/cache.h"
+
+typedef struct _QuantumState
+{
+  EndianType
+    endian;
+
+  double
+    minimum,
+    scale,
+    inverse_scale;
+
+  unsigned long
+    pixel,
+    bits;
+
+  const unsigned long
+    *mask;
+} QuantumState;
+
+struct _QuantumInfo
+{
+  unsigned long
+    depth,
+    quantum;
+
+  QuantumFormatType
+    format;
+
+  double
+    minimum,
+    maximum,
+    scale;
+
+  size_t
+    pad;
+
+  MagickBooleanType
+    min_is_white,
+    pack;
+
+  QuantumAlphaType
+    alpha_type;
+
+  unsigned long
+    number_threads;
+
+  unsigned char
+    **pixels;
+
+  size_t
+    extent;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    signature;
+};
+
+static inline MagickSizeType GetQuantumRange(const unsigned long depth)
+{
+  return((MagickSizeType) ((MagickULLConstant(1) << (depth-1))+
+    ((MagickULLConstant(1) << (depth-1))-1)));
+}
+
+static inline void InitializeQuantumState(const QuantumInfo *quantum_info,
+  const EndianType endian,QuantumState *quantum_state)
+{
+  static const unsigned long mask[32] =
+  {
+    0x00000000UL, 0x00000001UL, 0x00000003UL, 0x00000007UL, 0x0000000fUL,
+    0x0000001fUL, 0x0000003fUL, 0x0000007fUL, 0x000000ffUL, 0x000001ffUL,
+    0x000003ffUL, 0x000007ffUL, 0x00000fffUL, 0x00001fffUL, 0x00003fffUL,
+    0x00007fffUL, 0x0000ffffUL, 0x0001ffffUL, 0x0003ffffUL, 0x0007ffffUL,
+    0x000fffffUL, 0x001fffffUL, 0x003fffffUL, 0x007fffffUL, 0x00ffffffUL,
+    0x01ffffffUL, 0x03ffffffUL, 0x07ffffffUL, 0x0fffffffUL, 0x1fffffffUL,
+    0x3fffffffUL, 0x7fffffffUL
+  };
+
+  (void) ResetMagickMemory(quantum_state,0,sizeof(&quantum_state));
+  quantum_state->endian=endian;
+  quantum_state->minimum=quantum_info->minimum;
+  quantum_state->scale=quantum_info->scale;
+  quantum_state->inverse_scale=0.0;
+  if (quantum_state->scale != 0.0)
+    quantum_state->inverse_scale=1.0/quantum_state->scale;
+  quantum_state->bits=0;
+  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 long 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 long *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 long) (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)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((QuantumAny) (((MagickRealType) range*quantum)/QuantumRange+0.5));
+#else
+  return((QuantumAny) (((MagickRealType) range*quantum)/QuantumRange));
+#endif
+}
+
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+static inline Quantum ScaleCharToQuantum(const unsigned char value)
+{
+  return((Quantum) value);
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned long 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 defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) value);
+#else
+  if (value <= 0.0)
+    return(0);
+  if ((value+0.5) >= MaxMap)
+    return((Quantum) QuantumRange);
+  return((Quantum) (value+0.5));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) (16843009UL*quantum));
+#else
+  if (quantum <= 0.0)
+    return(0UL);
+  if ((16843009.0*quantum) >= 4294967295.0)
+    return(4294967295UL);
+  return((unsigned long) (16843009.0*quantum+0.5));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum >= (Quantum) MaxMap)
+    return((unsigned long) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) quantum);
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned long) (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+128UL)/257UL));
+#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) (257UL*value));
+#else
+  return((Quantum) (257.0*value));
+#endif
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned long 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 defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) value);
+#else
+  if (value <= 0.0)
+    return(0);
+  if ((value+0.5) >= MaxMap)
+    return((Quantum) QuantumRange);
+  return((Quantum) (value+0.5));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) (65537UL*quantum));
+#else
+  if (quantum <= 0.0)
+    return(0UL);
+  if ((65537.0*quantum) >= 4294967295.0)
+    return(4294967295UL);
+  return((unsigned long) (65537.0*quantum+0.5));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum >= (Quantum) MaxMap)
+    return((unsigned long) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) quantum);
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned long) (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 long value)
+{
+  return((Quantum) value);
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (65537.0*value));
+#else
+  if (value <= 0.0)
+    return(0);
+  if ((value+0.5) >= MaxMap)
+    return(QuantumRange);
+  return((Quantum) (65537UL*value));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToLong(const Quantum quantum)
+{
+  return((unsigned long) quantum);
+}
+
+static inline unsigned long ScaleQuantumToMap(const Quantum quantum)
+{
+  if ((quantum/65537) >= MaxMap)
+    return((unsigned long) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) ((quantum+MagickULLConstant(32768))/
+    MagickULLConstant(65537)));
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned long) (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)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (MagickULLConstant(71777214294589695)*value));
+#else
+  return((Quantum) (71777214294589695.0*value));
+#endif
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned long value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (4294967295UL*value));
+#else
+  return((Quantum) (4294967295.0*value));
+#endif
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (281479271612415.0*value));
+#else
+  if (value <= 0.0)
+    return(0);
+  if ((value+0.5) >= MaxMap)
+    return(QuantumRange);
+  return((Quantum) (MagickULLConstant(281479271612415)*value));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) ((quantum+2147483648.0)/4294967297.0));
+#else
+  return((unsigned long) (quantum/4294967297.0+0.5));
+#endif
+}
+
+static inline unsigned long ScaleQuantumToMap(const Quantum quantum)
+{
+  if ((quantum/281479271612415.0) >= MaxMap)
+    return((unsigned long) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned long) ((quantum+2147450879.0)/281479271612415.0));
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned long) (quantum/281479271612415.0)+0.5);
+#endif
+}
+
+static inline unsigned short ScaleQuantumToShort(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned short) ((quantum+2147450879.0)/281479271612415.0));
+#else
+  return((unsigned short) (quantum/281479271612415.0+0.5));
+#endif
+}
+
+static inline Quantum ScaleShortToQuantum(const unsigned short value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (MagickULLConstant(281479271612415)*value));
+#else
+  return((Quantum) (281479271612415.0*value));
+#endif
+}
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/quantum.c b/magick/quantum.c
new file mode 100644
index 0000000..4e57dee
--- /dev/null
+++ b/magick/quantum.c
@@ -0,0 +1,844 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/color-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/cache.h"
+#include "magick/constitute.h"
+#include "magick/delegate.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/pixel.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/statistic.h"
+#include "magick/stream.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/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 unsigned long MagickMax(const unsigned long x,
+  const unsigned long 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 long
+    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,
+    sizeof(*quantum_info->pixels));
+  for (i=0; i < (long) 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 long
+    i;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  assert(quantum_info->pixels != (unsigned char **) NULL);
+  for (i=0; i < (long) quantum_info->number_threads; i++)
+  {
+    assert(quantum_info->pixels[i][quantum_info->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 RGBAQuantum: packet_size=4; break;
+    case RGBOQuantum: 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*((image->depth+7)/8)));
+  return((size_t) ((packet_size*image->columns*image->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) ParseMagickOption(
+      MagickQuantumFormatOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"quantum:minimum");
+  if (option != (char *) NULL)
+    quantum_info->minimum=atof(option);
+  option=GetImageOption(image_info,"quantum:maximum");
+  if (option != (char *) NULL)
+    quantum_info->maximum=atof(option);
+  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=atof(option);
+  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)
+{
+  long
+    id;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  id=GetOpenMPThreadId();
+  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 (IsGrayImage(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 unsigned long 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 unsigned long 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
+        quantum_info->depth=32;
+    }
+  if (quantum_info->pixels != (unsigned char **) NULL)
+    DestroyQuantumPixels(quantum_info);
+  status=AcquireQuantumPixels(quantum_info,(quantum_info->pad+5)*image->columns*
+    ((quantum_info->depth+7)/8));
+  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 unsigned long 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 unsigned long 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 unsigned long 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 unsigned long 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/magick/quantum.h b/magick/quantum.h
new file mode 100644
index 0000000..685ed11
--- /dev/null
+++ b/magick/quantum.h
@@ -0,0 +1,180 @@
+/*
+  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 "magick/semaphore.h"
+
+typedef enum
+{
+  UndefinedEndian,
+  LSBEndian,
+  MSBEndian
+} EndianType;
+
+typedef enum
+{
+  UndefinedQuantumAlpha,
+  AssociatedQuantumAlpha,
+  DisassociatedQuantumAlpha
+} QuantumAlphaType;
+
+typedef enum
+{
+  UndefinedQuantumFormat,
+  FloatingPointQuantumFormat,
+  SignedQuantumFormat,
+  UnsignedQuantumFormat
+} QuantumFormatType;
+
+typedef enum
+{
+  UndefinedQuantum,
+  AlphaQuantum,
+  BlackQuantum,
+  BlueQuantum,
+  CMYKAQuantum,
+  CMYKQuantum,
+  CyanQuantum,
+  GrayAlphaQuantum,
+  GrayQuantum,
+  GreenQuantum,
+  IndexAlphaQuantum,
+  IndexQuantum,
+  MagentaQuantum,
+  OpacityQuantum,
+  RedQuantum,
+  RGBAQuantum,
+  RGBOQuantum,
+  RGBQuantum,
+  YellowQuantum,
+  GrayPadQuantum,  /* deprecated */
+  RGBPadQuantum,
+  CbYCrYQuantum,
+  CbYCrQuantum,
+  CbYCrAQuantum,
+  CMYKOQuantum
+} QuantumType;
+
+typedef struct _QuantumInfo
+  QuantumInfo;
+
+static inline Quantum RoundToQuantum(const MagickRealType value)
+{
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) value);
+#else
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= 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(0UL);
+  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+2155839615.0)/71777214294589695.0));
+#else
+  return((unsigned char) (quantum/71777214294589695.0+0.5));
+#endif
+}
+#endif
+
+extern MagickExport MagickBooleanType
+  SetQuantumDepth(const Image *,QuantumInfo *,const unsigned long),
+  SetQuantumFormat(const Image *,QuantumInfo *,const QuantumFormatType),
+  SetQuantumPad(const Image *,QuantumInfo *,const unsigned long);
+
+extern MagickExport QuantumInfo
+  *AcquireQuantumInfo(const ImageInfo *,Image *),
+  *DestroyQuantumInfo(QuantumInfo *);
+
+extern MagickExport QuantumType
+  GetQuantumType(Image *,ExceptionInfo *);
+
+extern MagickExport size_t
+  ExportQuantumPixels(const Image *,const 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 unsigned long),
+  SetQuantumScale(QuantumInfo *,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/random-private.h b/magick/random-private.h
new file mode 100644
index 0000000..ee13553
--- /dev/null
+++ b/magick/random-private.h
@@ -0,0 +1,70 @@
+/*
+  Copyright 1999-2009 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 "magick/thread-private.h"
+
+static inline RandomInfo **DestroyRandomInfoThreadSet(
+  RandomInfo **random_info)
+{
+  register long
+    i;
+
+  assert(random_info != (RandomInfo **) NULL);
+  for (i=0; i < (long) 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 long
+    i;
+
+  RandomInfo
+    **random_info;
+
+  unsigned long
+    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 < (long) 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/magick/random.c b/magick/random.c
new file mode 100644
index 0000000..b459fc0
--- /dev/null
+++ b/magick/random.c
@@ -0,0 +1,867 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                 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-2009 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 <[email protected]>
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#if defined(__VMS)
+#include <time.h>
+#endif
+#if defined(__MINGW32__)
+#include <sys/time.h>
+#endif
+#include "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/random_.h"
+#include "magick/resource_.h"
+#include "magick/signature-private.h"
+#include "magick/string_.h"
+#include "magick/thread_.h"
+#include "magick/thread-private.h"
+#include "magick/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;
+
+  long
+    timestamp;
+
+  unsigned long
+    signature;
+};
+
+/*
+  External declarations.
+*/
+#if defined(__APPLE__)
+#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 *) AcquireAlignedMemory(1,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=(long) 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);
+  (void) 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);
+  (void) UnlockSemaphoreInfo(random_info->semaphore);
+  DestroySemaphoreInfo(&random_info->semaphore);
+  random_info=(RandomInfo *) RelinquishAlignedMemory(random_info);
+  return(random_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y R a n d o m R e s e r v i o r                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyRandomReservoir() deallocates memory associated with the random
+%  reservoir.
+%
+%  The format of the DestroyRandomReservoir method is:
+%
+%      DestroyRandomReservoir(void)
+%
+*/
+MagickExport void DestroyRandomReservoir(void)
+{
+  AcquireSemaphoreInfo(&random_semaphore);
+  (void) UnlockSemaphoreInfo(random_semaphore);
+  DestroySemaphoreInfo(&random_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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.
+%
+*/
+
+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);
+}
+
+static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
+{
+#define MaxEntropyExtent  64
+
+  long
+    pid;
+
+  MagickThreadType
+    tid;
+
+  StringInfo
+    *chaos,
+    *entropy;
+
+  unsigned long
+    nanoseconds,
+    seconds;
+
+  /*
+    Initialize random reservoir.
+  */
+  entropy=AcquireStringInfo(0);
+  (void) 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=(long) 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,0) == 0)
+      {
+        seconds=timer.tv_sec;
+        nanoseconds=1000UL*timer.tv_usec;
+      }
+  }
+#endif
+#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_HIGHRES)
+  {
+    struct timespec
+      timer;
+
+    if (clock_gettime(CLOCK_HIGHRES,&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(__WINDOWS__)
+  {
+    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 long
+          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);
+  (void) 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long
+    i;
+
+  unsigned char
+    *datum;
+
+  datum=GetStringInfoDatum(nonce);
+  for (i=(long) (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;
+  (void) 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];
+    }
+  (void) 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/magick/random_.h b/magick/random_.h
new file mode 100644
index 0000000..867d5e9
--- /dev/null
+++ b/magick/random_.h
@@ -0,0 +1,57 @@
+/*
+  Copyright 1999-2009 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 "magick/string_.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _RandomInfo
+  RandomInfo;
+
+/*
+  Method declarations.
+*/
+extern MagickExport double
+  GetRandomValue(RandomInfo *),
+  GetPseudoRandomValue(RandomInfo *);
+
+extern MagickExport RandomInfo
+  *AcquireRandomInfo(void),
+  *DestroyRandomInfo(RandomInfo *);
+
+extern MagickExport StringInfo
+  *GetRandomKey(RandomInfo *,const size_t);
+
+extern MagickExport void
+  DestroyRandomReservoir(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/magick/registry.c b/magick/registry.c
new file mode 100644
index 0000000..9008a97
--- /dev/null
+++ b/magick/registry.c
@@ -0,0 +1,493 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/registry.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _RegistryInfo
+{
+  RegistryType
+    type;
+
+  void
+    *value;
+
+  unsigned long
+    signature;
+} RegistryInfo;
+
+/*
+  Static declarations.
+*/
+static SplayTreeInfo
+  *registry = (SplayTreeInfo *) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e R e g i s t r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageRegistry() releases memory associated with the image registry.
+%
+%  The format of the DestroyDefines method is:
+%
+%      void DestroyImageRegistry(void)
+%
+*/
+MagickExport void DestroyImageRegistry(void)
+{
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (registry != (void *) NULL)
+    registry=DestroySplayTree(registry);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 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 == (void *) NULL)
+    registry=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+      DestroyRegistryNode);
+  status=AddValueToSplayTree(registry,ConstantString(key),registry_info);
+  return(status);
+}
diff --git a/magick/registry.h b/magick/registry.h
new file mode 100644
index 0000000..cf2876c
--- /dev/null
+++ b/magick/registry.h
@@ -0,0 +1,52 @@
+/*
+  Copyright 1999-2009 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 *),
+  SetImageRegistry(const RegistryType,const char *,const void *,
+    ExceptionInfo *);
+
+extern MagickExport void
+  DestroyImageRegistry(void),
+  *GetImageRegistry(const RegistryType,const char *,ExceptionInfo *),
+  *RemoveImageRegistry(const char *),
+  ResetImageRegistryIterator(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/resample-private.h b/magick/resample-private.h
new file mode 100644
index 0000000..460a7fd
--- /dev/null
+++ b/magick/resample-private.h
@@ -0,0 +1,75 @@
+/*
+  Copyright 1999-2009 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 "magick/thread-private.h"
+
+static inline ResampleFilter **DestroyResampleFilterThreadSet(
+  ResampleFilter **filter)
+{
+  register long
+    i;
+
+  assert(filter != (ResampleFilter **) NULL);
+  for (i=0; i < (long) 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 MagickBooleanType interpolate,
+  ExceptionInfo *exception)
+{
+  register long
+    i;
+
+  ResampleFilter
+    **filter;
+
+  unsigned long
+    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 < (long) number_threads; i++)
+  {
+    filter[i]=AcquireResampleFilter(image,exception);
+    if (filter[i] == (ResampleFilter *) NULL)
+      return(DestroyResampleFilterThreadSet(filter));
+    if (interpolate != MagickFalse)
+      SetResampleFilter(filter[i],PointFilter,1.0);
+  }
+  return(filter);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/resample.c b/magick/resample.c
new file mode 100644
index 0000000..b7242a9
--- /dev/null
+++ b/magick/resample.c
@@ -0,0 +1,1549 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/color-private.h"
+#include "magick/cache.h"
+#include "magick/draw.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/resample.h"
+#include "magick/resize.h"
+#include "magick/resize-private.h"
+#include "magick/transform.h"
+#include "magick/signature-private.h"
+/*
+  Typedef declarations.
+*/
+#define WLUT_WIDTH 1024
+struct _ResampleFilter
+{
+  Image
+    *image;
+
+  CacheView
+    *view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    debug;
+
+  /* Information about image being resampled */
+  long
+    image_area;
+
+  InterpolatePixelMethod
+    interpolate;
+
+  VirtualPixelMethod
+    virtual_pixel;
+
+  FilterTypes
+    filter;
+
+  /* processing settings needed */
+  MagickBooleanType
+    limit_reached,
+    do_interpolate,
+    average_defined;
+
+  MagickPixelPacket
+    average_pixel;
+
+  /* current ellipitical area being resampled around center point */
+  double
+    A, B, C,
+    sqrtA, sqrtC, sqrtU, slope;
+
+  /* LUT of weights for filtered average in elliptical area */
+  double
+    filter_lut[WLUT_WIDTH],
+    support;
+
+  unsigned long
+    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);
+%      for (y=0; y < (long) image->rows; y++) {
+%        for (x=0; x < (long) image->columns; x++) {
+%          X= ....;   Y= ....;
+%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
+%          (void) ResamplePixelColor(resample_filter,X,Y,&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->image=ReferenceImage((Image *) image);
+  resample_filter->view=AcquireCacheView(resample_filter->image);
+  resample_filter->exception=exception;
+
+  resample_filter->debug=IsEventLogging();
+  resample_filter->signature=MagickSignature;
+
+  resample_filter->image_area = (long) resample_filter->image->columns *
+    resample_filter->image->rows;
+  resample_filter->average_defined = MagickFalse;
+
+  /* initialise the resampling filter settings */
+  SetResampleFilter(resample_filter, resample_filter->image->filter,
+    resample_filter->image->blur);
+  resample_filter->interpolate = resample_filter->image->interpolate;
+  resample_filter->virtual_pixel=GetImageVirtualPixelMethod(image);
+
+  /* init scale to a default of a unit circle */
+  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
+
+  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);
+  resample_filter->signature=(~MagickSignature);
+  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
+  return(resample_filter);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e R e s a m p l e F i l t e r                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolateResampleFilter() 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 InterpolateResampleFilter method is:
+%
+%      MagickBooleanType InterpolateResampleFilter(
+%        ResampleInfo *resample_filter,const InterpolatePixelMethod method,
+%        const double x,const double y,MagickPixelPacket *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: the resample filter.
+%
+%    o method: the pixel clor interpolation method.
+%
+%    o x,y: A double representing the current (x,y) position of the pixel.
+%
+%    o pixel: return the interpolated pixel here.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static void BicubicInterpolate(const MagickPixelPacket *pixels,const double dx,
+  MagickPixelPacket *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].opacity-pixels[2].opacity)-(pixels[0].opacity-pixels[1].opacity);
+  q=(pixels[0].opacity-pixels[1].opacity)-p;
+  r=pixels[2].opacity-pixels[0].opacity;
+  s=pixels[1].opacity;
+  pixel->opacity=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  if (pixel->colorspace == CMYKColorspace)
+    {
+      p=(pixels[3].index-pixels[2].index)-(pixels[0].index-pixels[1].index);
+      q=(pixels[0].index-pixels[1].index)-p;
+      r=pixels[2].index-pixels[0].index;
+      s=pixels[1].index;
+      pixel->index=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+    }
+}
+
+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 long NearestNeighbor(MagickRealType x)
+{
+  if (x >= 0.0)
+    return((long) (x+0.5));
+  return((long) (x-0.5));
+}
+
+static MagickBooleanType InterpolateResampleFilter(
+  ResampleFilter *resample_filter,const InterpolatePixelMethod method,
+  const double x,const double y,MagickPixelPacket *pixel)
+{
+  MagickBooleanType
+    status;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i;
+
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+  status=MagickTrue;
+  switch (method)
+  {
+    case AverageInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[16];
+
+      MagickRealType
+        alpha[16],
+        gamma;
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x)-1,(long)
+        floor(y)-1,4,4,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      for (i=0; i < 16L; i++)
+      {
+        GetMagickPixelPacket(resample_filter->image,pixels+i);
+        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (resample_filter->image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (resample_filter->image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        gamma=alpha[i];
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        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->opacity+=0.0625*pixels[i].opacity;
+        if (resample_filter->image->colorspace == CMYKColorspace)
+          pixel->index+=gamma*0.0625*pixels[i].index;
+        p++;
+      }
+      break;
+    }
+    case BicubicInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[16],
+        u[4];
+
+      MagickRealType
+        alpha[16];
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x)-1,(long)
+        floor(y)-1,4,4,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      for (i=0; i < 16L; i++)
+      {
+        GetMagickPixelPacket(resample_filter->image,pixels+i);
+        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (resample_filter->image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (resample_filter->image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        p++;
+      }
+      delta.x=x-floor(x);
+      for (i=0; i < 4L; i++)
+        BicubicInterpolate(pixels+4*i,delta.x,u+i);
+      delta.y=y-floor(y);
+      BicubicInterpolate(u,delta.y,pixel);
+      break;
+    }
+    case BilinearInterpolatePixel:
+    default:
+    {
+      MagickPixelPacket
+        pixels[4];
+
+      MagickRealType
+        alpha[4],
+        gamma;
+
+      PointInfo
+        delta,
+        epsilon;
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x),(long)
+        floor(y),2,2,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      for (i=0; i < 4L; i++)
+      {
+        pixels[i].red=(MagickRealType) p[i].red;
+        pixels[i].green=(MagickRealType) p[i].green;
+        pixels[i].blue=(MagickRealType) p[i].blue;
+        pixels[i].opacity=(MagickRealType) p[i].opacity;
+        alpha[i]=1.0;
+      }
+      if (resample_filter->image->matte != MagickFalse)
+        for (i=0; i < 4L; i++)
+        {
+          alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p[i].opacity);
+          pixels[i].red*=alpha[i];
+          pixels[i].green*=alpha[i];
+          pixels[i].blue*=alpha[i];
+        }
+      if (indexes != (IndexPacket *) NULL)
+        for (i=0; i < 4L; i++)
+        {
+          pixels[i].index=(MagickRealType) indexes[i];
+          if (resample_filter->image->colorspace == CMYKColorspace)
+            pixels[i].index*=alpha[i];
+        }
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      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->opacity=(epsilon.y*(epsilon.x*pixels[0].opacity+delta.x*
+        pixels[1].opacity)+delta.y*(epsilon.x*pixels[2].opacity+delta.x*
+        pixels[3].opacity));
+      if (resample_filter->image->colorspace == CMYKColorspace)
+        pixel->index=gamma*(epsilon.y*(epsilon.x*pixels[0].index+delta.x*
+          pixels[1].index)+delta.y*(epsilon.x*pixels[2].index+delta.x*
+          pixels[3].index));
+      break;
+    }
+    case FilterInterpolatePixel:
+    {
+      Image
+        *excerpt_image,
+        *filter_image;
+
+      MagickPixelPacket
+        pixels[1];
+
+      RectangleInfo
+        geometry;
+
+      CacheView
+        *filter_view;
+
+      geometry.width=4L;
+      geometry.height=4L;
+      geometry.x=(long) floor(x)-1L;
+      geometry.y=(long) floor(y)-1L;
+      excerpt_image=ExcerptImage(resample_filter->image,&geometry,
+        resample_filter->exception);
+      if (excerpt_image == (Image *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      filter_image=ResizeImage(excerpt_image,1,1,resample_filter->image->filter,
+        resample_filter->image->blur,resample_filter->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,
+        resample_filter->exception);
+      if (p != (const PixelPacket *) NULL)
+        {
+          indexes=GetVirtualIndexQueue(filter_image);
+          GetMagickPixelPacket(resample_filter->image,pixels);
+          SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
+        }
+      filter_view=DestroyCacheView(filter_view);
+      filter_image=DestroyImage(filter_image);
+      break;
+    }
+    case IntegerInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[1];
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x),(long)
+        floor(y),1,1,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      GetMagickPixelPacket(resample_filter->image,pixels);
+      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
+      break;
+    }
+    case MeshInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[4];
+
+      MagickRealType
+        alpha[4],
+        gamma;
+
+      PointInfo
+        delta,
+        luminance;
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x),(long)
+        floor(y),2,2,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      for (i=0; i < 4L; i++)
+      {
+        GetMagickPixelPacket(resample_filter->image,pixels+i);
+        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
+        alpha[i]=1.0;
+        if (resample_filter->image->matte != MagickFalse)
+          {
+            alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+            pixels[i].red*=alpha[i];
+            pixels[i].green*=alpha[i];
+            pixels[i].blue*=alpha[i];
+            if (resample_filter->image->colorspace == CMYKColorspace)
+              pixels[i].index*=alpha[i];
+          }
+        p++;
+      }
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      luminance.x=MagickPixelLuminance(pixels+0)-MagickPixelLuminance(pixels+3);
+      luminance.y=MagickPixelLuminance(pixels+1)-MagickPixelLuminance(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->opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
+                pixels[3].opacity,pixels[0].opacity);
+              if (resample_filter->image->colorspace == CMYKColorspace)
+                pixel->index=gamma*MeshInterpolate(&delta,pixels[2].index,
+                  pixels[3].index,pixels[0].index);
+            }
+          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->opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
+                pixels[0].opacity,pixels[3].opacity);
+              if (resample_filter->image->colorspace == CMYKColorspace)
+                pixel->index=gamma*MeshInterpolate(&delta,pixels[1].index,
+                  pixels[0].index,pixels[3].index);
+            }
+        }
+      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->opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
+                pixels[1].opacity,pixels[2].opacity);
+              if (resample_filter->image->colorspace == CMYKColorspace)
+                pixel->index=gamma*MeshInterpolate(&delta,pixels[0].index,
+                  pixels[1].index,pixels[2].index);
+            }
+          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->opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
+                pixels[2].opacity,pixels[1].opacity);
+              if (resample_filter->image->colorspace == CMYKColorspace)
+                pixel->index=gamma*MeshInterpolate(&delta,pixels[3].index,
+                  pixels[2].index,pixels[1].index);
+            }
+        }
+      break;
+    }
+    case NearestNeighborInterpolatePixel:
+    {
+      MagickPixelPacket
+        pixels[1];
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,NearestNeighbor(x),
+        NearestNeighbor(y),1,1,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      GetMagickPixelPacket(resample_filter->image,pixels);
+      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
+      break;
+    }
+    case SplineInterpolatePixel:
+    {
+      long
+        j,
+        n;
+
+      MagickPixelPacket
+        pixels[16];
+
+      MagickRealType
+        alpha[16],
+        dx,
+        dy,
+        gamma;
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(resample_filter->view,(long) floor(x)-1,(long)
+        floor(y)-1,4,4,resample_filter->exception);
+      if (p == (const PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+      n=0;
+      delta.x=x-floor(x);
+      delta.y=y-floor(y);
+      for (i=(-1); i < 3L; i++)
+      {
+        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
+        for (j=(-1); j < 3L; j++)
+        {
+          GetMagickPixelPacket(resample_filter->image,pixels+n);
+          SetMagickPixelPacket(resample_filter->image,p,indexes+n,pixels+n);
+          alpha[n]=1.0;
+          if (resample_filter->image->matte != MagickFalse)
+            {
+              alpha[n]=QuantumScale*((MagickRealType) QuantumRange-p->opacity);
+              pixels[n].red*=alpha[n];
+              pixels[n].green*=alpha[n];
+              pixels[n].blue*=alpha[n];
+              if (resample_filter->image->colorspace == CMYKColorspace)
+                pixels[n].index*=alpha[n];
+            }
+          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
+          gamma=alpha[n];
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          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 (resample_filter->image->matte != MagickFalse)
+            pixel->opacity+=dx*dy*pixels[n].opacity;
+          if (resample_filter->image->colorspace == CMYKColorspace)
+            pixel->index+=gamma*dx*dy*pixels[n].index;
+          n++;
+          p++;
+        }
+      }
+      break;
+    }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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,MagickPixelPacket *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,
+  MagickPixelPacket *pixel)
+{
+  MagickBooleanType
+    status;
+
+  long u,v, uw,v1,v2, hit;
+  double u1;
+  double U,V,Q,DQ,DDQ;
+  double divisor_c,divisor_m;
+  register double weight;
+  register const PixelPacket *pixels;
+  register const IndexPacket *indexes;
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  status=MagickTrue;
+  GetMagickPixelPacket(resample_filter->image,pixel);
+  if ( resample_filter->do_interpolate ) {
+    status=InterpolateResampleFilter(resample_filter,
+      resample_filter->interpolate,u0,v0,pixel);
+    return(status);
+  }
+
+  /*
+    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 ConstantVirtualPixelMethod:
+    case TransparentVirtualPixelMethod:
+    case BlackVirtualPixelMethod:
+    case GrayVirtualPixelMethod:
+    case WhiteVirtualPixelMethod:
+    case MaskVirtualPixelMethod:
+      if ( resample_filter->limit_reached
+           || u0 + resample_filter->sqrtC < 0.0
+           || u0 - resample_filter->sqrtC > (double) resample_filter->image->columns
+           || v0 + resample_filter->sqrtA < 0.0
+           || v0 - resample_filter->sqrtA > (double) resample_filter->image->rows
+           )
+        hit++;
+      break;
+
+    case UndefinedVirtualPixelMethod:
+    case EdgeVirtualPixelMethod:
+      if (    ( u0 + resample_filter->sqrtC < 0.0 && v0 + resample_filter->sqrtA < 0.0 )
+           || ( u0 + resample_filter->sqrtC < 0.0
+                && v0 - resample_filter->sqrtA > (double) resample_filter->image->rows )
+           || ( u0 - resample_filter->sqrtC > (double) resample_filter->image->columns
+                && v0 + resample_filter->sqrtA < 0.0 )
+           || ( u0 - resample_filter->sqrtC > (double) resample_filter->image->columns
+                && v0 - resample_filter->sqrtA > (double) resample_filter->image->rows )
+           )
+        hit++;
+      break;
+    case HorizontalTileVirtualPixelMethod:
+      if (    v0 + resample_filter->sqrtA < 0.0
+           || v0 - resample_filter->sqrtA > (double) resample_filter->image->rows
+           )
+        hit++;  /* outside the horizontally tiled images. */
+      break;
+    case VerticalTileVirtualPixelMethod:
+      if (    u0 + resample_filter->sqrtC < 0.0
+           || u0 - resample_filter->sqrtC > (double) resample_filter->image->columns
+           )
+        hit++;  /* outside the vertically tiled images. */
+      break;
+    case DitherVirtualPixelMethod:
+      if (    ( u0 + resample_filter->sqrtC < -32.0 && v0 + resample_filter->sqrtA < -32.0 )
+           || ( u0 + resample_filter->sqrtC < -32.0
+                && v0 - resample_filter->sqrtA > (double) resample_filter->image->rows+32.0 )
+           || ( u0 - resample_filter->sqrtC > (double) resample_filter->image->columns+32.0
+                && v0 + resample_filter->sqrtA < -32.0 )
+           || ( u0 - resample_filter->sqrtC > (double) resample_filter->image->columns+32.0
+                && v0 - resample_filter->sqrtA > (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=InterpolateResampleFilter(resample_filter,IntegerInterpolatePixel,
+      u0,v0,pixel);
+    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, for the right 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=InterpolateResampleFilter(resample_filter,
+          AverageInterpolatePixel,u0,v0,pixel);
+        break;
+      case HorizontalTileVirtualPixelMethod:
+      case VerticalTileVirtualPixelMethod:
+        /* just return the background pixel - Is there more direct way? */
+        status=InterpolateResampleFilter(resample_filter,
+           IntegerInterpolatePixel,(double)-1,(double)-1,pixel);
+        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;
+
+          GetMagickPixelPacket(resample_filter->image,
+                (MagickPixelPacket *)&(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=(PixelPacket *)GetCacheViewVirtualPixels(average_view,0,0,1,1,
+            resample_filter->exception);
+          if (pixels == (const PixelPacket *) NULL) {
+            average_view=DestroyCacheView(average_view);
+            average_image=DestroyImage(average_image);
+            *pixel=resample_filter->average_pixel; /* FAILED */
+            break;
+          }
+          indexes=(IndexPacket *) GetCacheViewAuthenticIndexQueue(average_view);
+          SetMagickPixelPacket(resample_filter->image,pixels,indexes,
+            &(resample_filter->average_pixel));
+          average_view=DestroyCacheView(average_view);
+          average_image=DestroyImage(average_image);
+#if 0
+          /* CheckerTile should average the image with background color */
+          //if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod ) {
+#if 0
+            resample_filter->average_pixel.red =
+                      ( resample_filter->average_pixel.red +
+                          resample_filter->image->background_color.red ) /2;
+            resample_filter->average_pixel.green =
+                      ( resample_filter->average_pixel.green +
+                          resample_filter->image->background_color.green ) /2;
+            resample_filter->average_pixel.blue =
+                      ( resample_filter->average_pixel.blue +
+                          resample_filter->image->background_color.blue ) /2;
+            resample_filter->average_pixel.matte =
+                      ( resample_filter->average_pixel.matte +
+                          resample_filter->image->background_color.matte ) /2;
+            resample_filter->average_pixel.black =
+                      ( resample_filter->average_pixel.black +
+                          resample_filter->image->background_color.black ) /2;
+#else
+            resample_filter->average_pixel =
+                          resample_filter->image->background_color;
+#endif
+          }
+#endif
+        }
+        *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 (resample_filter->image->matte != MagickFalse) pixel->opacity = 0.0;
+  if (resample_filter->image->colorspace == CMYKColorspace) pixel->index = 0.0;
+
+  /*
+    Determine the parellelogram bounding box fitted to the ellipse
+    centered at u0,v0.  This area is bounding by the lines...
+        v = +/- sqrt(A)
+        u = -By/2A  +/- sqrt(F/A)
+    Which has been pre-calculated above.
+  */
+  v1 = (long)(v0 - resample_filter->sqrtA);               /* range of scan lines */
+  v2 = (long)(v0 + resample_filter->sqrtA + 1);
+
+  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->sqrtU; /* start of scanline for v=v1 */
+  uw = (long)(2*resample_filter->sqrtU)+1;       /* width of parallelogram */
+
+  /*
+    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++, u1+=resample_filter->slope ) {
+    u = (long)u1;       /* first pixel in scanline  ( floor(u1) ) */
+    U = (double)u-u0;   /* location of that pixel, relative to u0,v0 */
+    V = (double)v-v0;
+
+    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
+    Q = U*(resample_filter->A*U + resample_filter->B*V) + 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,(unsigned long) uw,
+      1,resample_filter->exception);
+    if (pixels == (const PixelPacket *) NULL)
+      return(MagickFalse);
+    indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
+
+    /* count up the weighted pixel colors */
+    for( u=0; u<uw; u++ ) {
+      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
+      if ( Q < (double)WLUT_WIDTH ) {
+        weight = resample_filter->filter_lut[(int)Q];
+
+        pixel->opacity  += weight*pixels->opacity;
+        divisor_m += weight;
+
+        if (resample_filter->image->matte != MagickFalse)
+          weight *= QuantumScale*((MagickRealType)(QuantumRange-pixels->opacity));
+        pixel->red   += weight*pixels->red;
+        pixel->green += weight*pixels->green;
+        pixel->blue  += weight*pixels->blue;
+        if (resample_filter->image->colorspace == CMYKColorspace)
+          pixel->index += weight*(*indexes);
+        divisor_c += weight;
+
+        hit++;
+      }
+      pixels++;
+      indexes++;
+      Q += DQ;
+      DQ += DDQ;
+    }
+  }
+
+  /*
+    Result sanity check -- this should NOT happen
+  */
+  if ( hit < 4 || divisor_c < 1.0 ) {
+    /* not enough pixels in resampling, resort to direct interpolation */
+    status=InterpolateResampleFilter(resample_filter,
+      resample_filter->interpolate,u0,v0,pixel);
+    return status;
+  }
+
+  /*
+    Finialize results of resampling
+  */
+  divisor_m = 1.0/divisor_m;
+  pixel->opacity = (MagickRealType) RoundToQuantum(divisor_m*pixel->opacity);
+  divisor_c = 1.0/divisor_c;
+  pixel->red   = (MagickRealType) RoundToQuantum(divisor_c*pixel->red);
+  pixel->green = (MagickRealType) RoundToQuantum(divisor_c*pixel->green);
+  pixel->blue  = (MagickRealType) RoundToQuantum(divisor_c*pixel->blue);
+  if (resample_filter->image->colorspace == CMYKColorspace)
+    pixel->index = (MagickRealType) RoundToQuantum(divisor_c*pixel->index);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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)
+%  Then the scaling vectors dx,dy (in u,v space) are the derivitives...
+%      du/dx, dv/dx     and    du/dy, dv/dy
+%  If the scaling is only othogonally aligned then...
+%      dv/dx = 0   and   du/dy  =  0
+%  Producing an othogonally alligned ellipse 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, EG: U(x,y), V(x,y).  Caution is advised if you are trying to
+%  define the ellipse directly from scaling vectors.
+%
+%  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 partial derivitives or scaling vectors for resampling.
+%           dx = du/dx, dv/dx    and  dy = du/dy, dv/dy
+%
+%         The values are used to define the size and angle of the
+%         elliptical resampling area, centered on the lookup point.
+%
+*/
+MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
+  const double dux,const double duy,const double dvx,const double dvy)
+{
+  double A,B,C,F, area;
+
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  resample_filter->limit_reached = MagickFalse;
+  resample_filter->do_interpolate = MagickFalse;
+
+  /* A 'point' filter forces use of interpolation instead of area sampling */
+  if ( resample_filter->filter == PointFilter ) {
+    resample_filter->do_interpolate = MagickTrue;
+    return;
+  }
+
+  /* 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 0
+  /* Direct conversions of derivatives to elliptical coefficients
+     No scaling will result in F == 1.0 and a unit circle.
+  */
+  A = dvx*dvx+dvy*dvy;
+  B = (dux*dvx+duy*dvy)*-2.0;
+  C = dux*dux+duy*duy;
+  F = dux*dvy+duy*dvx;
+  F *= F;
+#define F_UNITY 1.0
+#else
+  /* This Paul Heckbert's recomended "Higher Quality EWA" formula, from page
+     60 in his thesis, which adds a unit circle to the elliptical area so are
+     to do both Reconstruction and Prefiltering of the pixels in the
+     resampling.  It also means it is likely to have at least 4 pixels within
+     the area of the ellipse, for weighted averaging.
+     No scaling will result if F == 4.0 and a circle of radius 2.0
+  */
+  A = dvx*dvx+dvy*dvy+1;
+  B = (dux*dvx+duy*dvy)*-2.0;
+  C = dux*dux+duy*duy+1;
+  F = A*C - B*B/4;
+#define F_UNITY 4.0
+#endif
+
+/* DEBUGGING OUTPUT */
+#if 0
+  fprintf(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy%lf;\n",
+       dux, dvx, duy, dvy);
+  fprintf(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
+#endif
+
+#if 0
+  /* Figure out the Ellipses Major and Minor Axis, and other info.
+     This information currently not needed at this time, but may be
+     needed later for better limit determination.
+  */
+  { double alpha, beta, gamma, Major, Minor;
+    double Eccentricity, Ellipse_Area, Ellipse_angle;
+    double max_horizontal_cross_section, max_vertical_cross_section;
+    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));
+
+    fprintf(stderr, "\tMajor=%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);
+
+    fprintf(stderr, "\tAngle=%lf Area=%lf\n",
+         RadiansToDegrees(Ellipse_angle), Ellipse_Area );
+
+    /* Ellipse limits */
+
+    /* orthogonal rectangle - improved ellipse */
+    max_horizontal_orthogonal = sqrt(A); /* = sqrt(4*A*F/(4*A*C-B*B)) */
+    max_vertical_orthogonal   = sqrt(C); /* = sqrt(4*C*F/(4*A*C-B*B)) */
+
+    /* parallelogram bounds -- what we are using */
+    max_horizontal_cross_section = sqrt(F/A);
+    max_vertical_cross_section   = sqrt(F/C);
+  }
+#endif
+
+  /* Is default elliptical area, too small? Image being magnified?
+     Switch to doing pure 'point' interpolation of the pixel.
+     That is turn off  EWA Resampling.
+  */
+  if ( F <= F_UNITY ) {
+    resample_filter->do_interpolate = MagickTrue;
+    return;
+  }
+
+
+  /* If F is impossibly large, we may as well not bother doing any
+   * form of resampling, as you risk an infinite resampled area.
+  */
+  if ( F > MagickHuge ) {
+    resample_filter->limit_reached = MagickTrue;
+    return;
+  }
+
+  /* Othogonal bounds of the ellipse */
+  resample_filter->sqrtA = sqrt(A)+1.0;     /* Vertical Orthogonal Limit */
+  resample_filter->sqrtC = sqrt(C)+1.0;     /* Horizontal Orthogonal Limit */
+
+  /* Horizontally aligned Parallelogram fitted to ellipse */
+  resample_filter->sqrtU = sqrt(F/A)+1.0;   /* Parallelogram Width */
+  resample_filter->slope = -B/(2*A);        /* Slope of the parallelogram */
+
+  /* The size of the area of the parallelogram we will be sampling */
+  area = 4 * resample_filter->sqrtA * resample_filter->sqrtU;
+
+  /* Absolute limit on the area to be resampled
+   * This limit needs more work, as it gets too slow for
+   * larger images involved with tiled views of the horizon. */
+  if ( area > 20.0*resample_filter->image_area ) {
+    resample_filter->limit_reached = MagickTrue;
+    return;
+  }
+
+  /* Scale ellipse formula to directly fit the Filter Lookup Table */
+  { register double scale;
+    scale = (double)WLUT_WIDTH/F;
+    resample_filter->A = A*scale;
+    resample_filter->B = B*scale;
+    resample_filter->C = C*scale;
+    /* ..ple_filter->F = WLUT_WIDTH; -- hardcoded */
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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)
+{
+  register int
+     Q;
+
+  double
+     r_scale;
+
+  ResizeFilter
+     *resize_filter;
+
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  resample_filter->filter = filter;
+
+  /* Scale radius so it equals 1.0, at edge of ellipse when a
+     default blurring factor of 1.0 is used.
+
+     Note that these filters are being used as a radial filter, not as
+     an othoginally alligned filter. How this effects results is still
+     being worked out.
+
+     Future: Direct use of teh resize filters in "resize.c" to set the lookup
+     table, based on the filters working support window.
+  */
+  r_scale = sqrt(1.0/(double)WLUT_WIDTH)/blur;
+  r_scale *= 2; /* for 2 pixel radius of Improved Elliptical Formula */
+
+  switch ( filter ) {
+  case PointFilter:
+    /* This equivelent to turning off the EWA algroithm.
+       Only Interpolated lookup will be used.  */
+    break;
+  default:
+    /*
+      Fill the LUT with a 1D resize filter function
+      But make the Sinc/Bessel tapered window 2.0
+      I also normalize the result so the filter is 1.0
+    */
+    resize_filter = AcquireResizeFilter(resample_filter->image,filter,
+         (MagickRealType)1.0,MagickTrue,resample_filter->exception);
+    if (resize_filter != (ResizeFilter *) NULL) {
+      resample_filter->support = GetResizeFilterSupport(resize_filter);
+      resample_filter->support /= blur; /* taken into account above */
+      resample_filter->support *= resample_filter->support;
+      resample_filter->support *= (double)WLUT_WIDTH/4;
+      if ( resample_filter->support >= (double)WLUT_WIDTH )
+           resample_filter->support = (double)WLUT_WIDTH;  /* hack */
+      for(Q=0; Q<WLUT_WIDTH; Q++)
+        if ( (double) Q < resample_filter->support )
+          resample_filter->filter_lut[Q] = (double)
+               GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
+        else
+          resample_filter->filter_lut[Q] = 0.0;
+      resize_filter = DestroyResizeFilter(resize_filter);
+      break;
+    }
+    else {
+      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
+           ModuleError, "UnableToSetFilteringValue",
+           "Fall back to default EWA gaussian filter");
+    }
+    /* FALLTHRU - on exception */
+  /*case GaussianFilter:*/
+  case UndefinedFilter:
+    /*
+      Create Normal Gaussian 2D Filter Weighted Lookup Table.
+      A normal EWA guassual lookup would use   exp(Q*ALPHA)
+      where  Q = distantce squared from 0.0 (center) to 1.0 (edge)
+      and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
+      However the table is of length 1024, and equates to a radius of 2px
+      thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
+    */
+    /*r_scale = -2.77258872223978123767*4/WLUT_WIDTH/blur/blur;*/
+    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;
+  }
+  if (GetImageArtifact(resample_filter->image,"resample:verbose")
+        != (const char *) NULL)
+    /* 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
+    */
+    for(Q=0; Q<WLUT_WIDTH; Q++)
+      printf("%lf\n", resample_filter->filter_lut[Q]
+                        /resample_filter->filter_lut[0] );
+  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() changes the interpolation method
+%  associated with the specified resample filter.
+%
+%  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;
+  (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
+  return(MagickTrue);
+}
diff --git a/magick/resample.h b/magick/resample.h
new file mode 100644
index 0000000..7be9c3b
--- /dev/null
+++ b/magick/resample.h
@@ -0,0 +1,91 @@
+/*
+  Copyright 1999-2009 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 <magick/cache-view.h>
+
+typedef enum
+{
+  UndefinedFilter,
+  PointFilter,
+  BoxFilter,
+  TriangleFilter,
+  HermiteFilter,
+  HanningFilter,
+  HammingFilter,
+  BlackmanFilter,
+  GaussianFilter,
+  QuadraticFilter,
+  CubicFilter,
+  CatromFilter,
+  MitchellFilter,
+  LanczosFilter,
+  BesselFilter,
+  SincFilter,
+  KaiserFilter,
+  WelshFilter,
+  ParzenFilter,
+  LagrangeFilter,
+  BohmanFilter,
+  BartlettFilter,
+  SentinelFilter  /* a count of all the filters, not a real filter */
+} FilterTypes;
+
+typedef enum
+{
+  UndefinedInterpolatePixel,
+  AverageInterpolatePixel,
+  BicubicInterpolatePixel,
+  BilinearInterpolatePixel,
+  FilterInterpolatePixel,
+  IntegerInterpolatePixel,
+  MeshInterpolatePixel,
+  NearestNeighborInterpolatePixel,
+  SplineInterpolatePixel
+} InterpolatePixelMethod;
+
+typedef struct _ResampleFilter
+  ResampleFilter;
+
+extern MagickExport MagickBooleanType
+  ResamplePixelColor(ResampleFilter *,const double,const double,
+    MagickPixelPacket *),
+  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/magick/resize-private.h b/magick/resize-private.h
new file mode 100644
index 0000000..f70a941
--- /dev/null
+++ b/magick/resize-private.h
@@ -0,0 +1,44 @@
+/*
+  Copyright 1999-2009 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/magick/resize.c b/magick/resize.c
new file mode 100644
index 0000000..f763c99
--- /dev/null
+++ b/magick/resize.c
@@ -0,0 +1,3021 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                 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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/memory_.h"
+#include "magick/pixel-private.h"
+#include "magick/property.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel.h"
+#include "magick/option.h"
+#include "magick/resample.h"
+#include "magick/resize.h"
+#include "magick/resize-private.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/utility.h"
+#include "magick/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 to scale to fit window support (usally 1.0) */
+    blur,      /* x-scale (blur-sharpen) */
+    cubic[8];  /* cubic coefficents for smooth Cubic filters */
+
+  unsigned long
+    signature;
+};
+
+/*
+  Forward declaractions.
+*/
+static MagickRealType
+  I0(MagickRealType x),
+  BesselOrderOne(MagickRealType);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 all 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)
+%
+%    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 posibly other
+%        pre-calculated information defineding the functions.
+%
+*/
+
+static MagickRealType Bessel(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    See Pratt "Digital Image Processing" p.97 for Bessel functions
+
+    This function actually a X-scaled Jinc(x) function.
+      http://mathworld.wolfram.com/JincFunction.html
+    And on page 11 of...
+      http://www.ph.ed.ac.uk/%7ewjh/teaching/mo/slides/lens/lens.pdf
+  */
+  if (x == 0.0)
+    return((MagickRealType) (MagickPI/4.0));
+  return(BesselOrderOne(MagickPI*x)/(2.0*x));
+}
+
+static MagickRealType Blackman(const MagickRealType x,
+     const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Blackman: 2rd Order cosine windowing function.
+  */
+  return(0.42+0.5*cos(MagickPI*(double) x)+0.08*cos(2.0*MagickPI*(double) x));
+}
+
+static MagickRealType Bohman(const MagickRealType x,
+     const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Bohman: 2rd Order cosine windowing function.
+  */
+  return((1-x)*cos(MagickPI*(double) x)+sin(MagickPI*(double) x)/MagickPI);
+}
+
+static MagickRealType Box(const MagickRealType magick_unused(x),
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Just return 1.0, filter will still be clipped by its support window.
+  */
+  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   Qualitively ideal Cubic Filter
+    Catmull-Rom         B= 0  C=1/2   Cublic Interpolation Function
+    Cubic B-Spline      B= 1  C= 0    Spline Approximation of Gaussian
+    Hermite             B= 0  C= 0    Quadratic Spline (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
+       P1 =         0
+       P2 = (-18 +12*B + 6*C )/6
+       P3 = ( 12 - 9*B - 6*C )/6
+       Q0 = (      8*B +24*C )/6
+       Q1 = (    -12*B -48*C )/6
+       Q2 = (      6*B +30*C )/6
+       Q3 = (    - 1*B - 6*C )/6
+
+    Which is 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->cubic[0]+x*(resize_filter->cubic[1]+x*
+      (resize_filter->cubic[2]+x*resize_filter->cubic[3])));
+  if (x < 2.0)
+    return(resize_filter->cubic[4] +x*(resize_filter->cubic[5]+x*
+      (resize_filter->cubic[6] +x*resize_filter->cubic[7])));
+  return(0.0);
+}
+
+static MagickRealType Gaussian(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  return(exp((double) (-2.0*x*x))*sqrt(2.0/MagickPI));
+}
+
+static MagickRealType Hanning(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    A Cosine windowing function.
+  */
+  return(0.5+0.5*cos(MagickPI*(double) x));
+}
+
+static MagickRealType Hamming(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    A offset Cosine windowing function.
+  */
+  return(0.54+0.46*cos(MagickPI*(double) x));
+}
+
+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 alphand the IOA pre-calculation, a 'expert' setting.
+  */
+  return(I0A*I0(Alpha*sqrt((double) (1.0-x*x))));
+}
+
+static MagickRealType Lagrange(const MagickRealType x,
+  const ResizeFilter *resize_filter)
+{
+  long
+    n,
+    order;
+
+  MagickRealType
+    value;
+
+  register long
+    i;
+
+  /*
+    Lagrange Piece-Wise 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, gives a lagrange-4 or piece-wise cubic functions
+
+      Note that n is the specific piece of the piece-wise function to calculate.
+
+      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=(long) (2.0*resize_filter->window_support);  /* number of pieces */
+  n=(long) ((1.0*order)/2.0+x);  /* which piece does x belong to */
+  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))
+{
+  /*
+    This function actually a X-scaled Sinc(x) function.
+  */
+  if (x == 0.0)
+    return(1.0);
+  return(sin(MagickPI*(double) x)/(MagickPI*(double) x));
+}
+
+static MagickRealType Triangle(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    1rd order (linear) B-Spline,  bilinear interpolation,
+    Tent 1D filter, or a Bartlett 2D Cone filter
+  */
+  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        Bessel
+%
+%  Windowed Sinc/Bessel Method
+%      Blackman     Hanning     Hamming
+%      Kaiser       Lancos (Sinc)
+%
+%  FIR filters are used as is, and are limited by that filters support window
+%  (unless over-ridden).  'Gaussian' while classed as an IIR filter, is also
+%  simply clipped by its support size (1.5).
+%
+%  Requesting a windowed filter will return either a windowed Sinc, for a one
+%  dimentional orthogonal filtering method, such as ResizeImage(), or a
+%  windowed Bessel for image operations requiring a two dimentional
+%  cylindrical filtering method, such a DistortImage().  Which function is
+%  is used set by the "cylindrical" boolean argument.
+%
+%  Directly requesting 'Sinc' or 'Bessel' will force the use of that filter
+%  function, with a default 'Blackman' windowing method.  This not however
+%  recommended as it removes the correct filter selection for different
+%  filtering image operations.  Selecting a window filtering method is better.
+%
+%  Lanczos is purely special case of a Sinc windowed Sinc, but defulting to
+%  a 3 lobe support, rather that the default 4 lobe support.
+%
+%  Special options can be used to override specific, or all the filter
+%  settings.   However doing so is not advisible unless you have expert
+%  knowledge of the use of resampling filtered techniques. Extreme caution is
+%  advised.
+%
+%    "filter:filter"    Select this function as the filter.
+%        If a "filter:window" operation is not provided, then no windowing
+%        will be performed on the selected filter, (support clipped)
+%
+%        This can be used to force the use of a windowing method as filter,
+%        request a 'Sinc' filter in a radially filtered operation, or the
+%        'Bessel' filter for a othogonal filtered operation.
+%
+%    "filter:window"   Select this windowing function for the filter.
+%        While any filter could be used as a windowing function,
+%        using that filters first lobe over the whole support window,
+%        using a non-windowing method is not advisible.
+%
+%    "filter:lobes"    Number of lobes to use for the Sinc/Bessel filter.
+%        This a simper method of setting filter support size that will
+%        correctly handle the Sinc/Bessel switch for an operators filtering
+%        requirements.
+%
+%    "filter:support"  Set the support size for filtering to the size given
+%        This not recomented for Sinc/Bessel windowed filters, but is
+%        used for simple filters like FIR filters, and the Gaussian Filter.
+%        This will override any 'filter:lobes' option.
+%
+%    "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 and Morie effects.
+%
+%    "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 winodw 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.  If unset this
+%        will equal the normal filter support size.
+%
+%    "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
+%
+%    "filter:verbose"   Output verbose plotting data for graphing the
+%         resulting filter over the whole support range (with blur effect).
+%
+%  Set a true un-windowed Sinc filter with 10 lobes (very slow)
+%     -set option:filter:filter  Sinc
+%     -set option:filter:lobes   8
+%
+%  For example force an 8 lobe Lanczos (Sinc or Bessel) filter...
+%     -filter Lanczos
+%     -set option:filter:lobes   8
+%
+%  The format of the AcquireResizeFilter method is:
+%
+%      ResizeFilter *AcquireResizeFilter(const Image *image,
+%        const FilterTypes filter_type, const MagickBooleanType radial,
+%        ExceptionInfo *exception)
+%
+%    o image: the image.
+%
+%    o filter: the filter type, defining a preset filter, window and support.
+%
+%    o blur: blur the filter by this amount, use 1.0 if unknown.
+%            Image artifact "filter:blur"  will override this old usage
+%
+%    o radial: 1D orthogonal filter (Sinc) or 2D radial filter (Bessel)
+%
+%    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;
+
+  long
+    filter_artifact;
+
+  MagickRealType
+    B,
+    C;
+
+  register ResizeFilter
+    *resize_filter;
+
+  /*
+    Table Mapping given Filter, into  Weighting and Windowing functions.
+    A 'Box' windowing function means its a simble non-windowed filter.
+    A 'Sinc' filter function (must be windowed) could be upgraded to a
+    'Bessel' filter if a "cylindrical" filter is requested, unless a "Sinc"
+    filter specifically request.
+  */
+  static struct
+  {
+    FilterTypes
+      filter,
+      window;
+  } const mapping[SentinelFilter] =
+  {
+    { UndefinedFilter, BoxFilter },  /* undefined */
+    { PointFilter,     BoxFilter },  /* special, nearest-neighbour filter */
+    { BoxFilter,       BoxFilter },  /* Box averaging Filter */
+    { TriangleFilter,  BoxFilter },  /* Linear Interpolation Filter */
+    { HermiteFilter,   BoxFilter },      /* Hermite interpolation filter */
+    { SincFilter,      HanningFilter },  /* Hanning -- Cosine-Sinc */
+    { SincFilter,      HammingFilter },  /* Hamming --  '' variation */
+    { SincFilter,      BlackmanFilter }, /* Blackman -- 2*Cosine-Sinc */
+    { GaussianFilter,  BoxFilter },      /* Gaussain Blurring filter */
+    { QuadraticFilter, BoxFilter },      /* Quadratic Gaussian approximation */
+    { CubicFilter,     BoxFilter },      /* Cubic Gaussian approximation */
+    { CatromFilter,    BoxFilter },      /* Cubic Interpolator */
+    { MitchellFilter,  BoxFilter },      /* 'ideal' Cubic Filter */
+    { LanczosFilter,   SincFilter },     /* Special, 3 lobed Sinc-Sinc */
+    { BesselFilter,    BlackmanFilter }, /* 3 lobed bessel -specific request */
+    { SincFilter,      BlackmanFilter }, /* 4 lobed sinc - specific request */
+    { SincFilter,      KaiserFilter },   /* Kaiser --  SqRoot-Sinc */
+    { SincFilter,      WelshFilter },    /* Welsh -- Parabolic-Sinc */
+    { SincFilter,      CubicFilter },    /* Parzen -- Cubic-Sinc */
+    { LagrangeFilter,  BoxFilter },      /* Lagrange self-windowing filter */
+    { SincFilter,      BohmanFilter },   /* Bohman -- 2*Cosine-Sinc */
+    { SincFilter,      TriangleFilter }  /* Bartlett -- Triangle-Sinc */
+  };
+  /*
+    Table maping the filter/window function from the above table to the actual
+    filter/window function call to use.  The default support size for that
+    filter as a weighting function, and the point to scale when that function
+    is used as a windowing function (typ 1.0).
+  */
+  static struct
+  {
+    MagickRealType
+      (*function)(const MagickRealType, const ResizeFilter*),
+      support,  /* default support size for function as a filter */
+      scale,    /* size windowing function, for scaling windowing function */
+      B,
+      C;        /* Cubic Filter factors for a CubicBC function, else ignored */
+  } const filters[SentinelFilter] =
+  {
+    { Box,       0.0f,  0.5f, 0.0f, 0.0f }, /* Undefined */
+    { Box,       0.0f,  0.5f, 0.0f, 0.0f }, /* Point */
+    { Box,       0.5f,  0.5f, 0.0f, 0.0f }, /* Box */
+    { Triangle,  1.0f,  1.0f, 0.0f, 0.0f }, /* Triangle */
+    { CubicBC,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hermite, Cubic B=C=0 */
+    { Hanning,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hanning, Cosine window */
+    { Hamming,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hamming, '' variation */
+    { Blackman,  1.0f,  1.0f, 0.0f, 0.0f }, /* Blackman, 2*cos window */
+    { Gaussian,  1.5f,  1.5f, 0.0f, 0.0f }, /* Gaussian */
+    { Quadratic, 1.5f,  1.5f, 0.0f, 0.0f }, /* Quadratic Gaussian */
+    { CubicBC,   2.0f,  2.0f, 1.0f, 0.0f }, /* B-Spline of Gaussian B=1 C=0 */
+    { CubicBC,   2.0f,  1.0f, 0.0f, 0.5f }, /* Catmull-Rom  B=0 C=1/2 */
+    { CubicBC,   2.0f,  1.0f, 1.0f/3.0f, 1.0f/3.0f }, /* Mitchel B=C=1/3 */
+    { Sinc,      3.0f,  1.0f, 0.0f, 0.0f }, /* Lanczos, 3 lobed Sinc-Sinc */
+    { Bessel,    3.2383f,1.2197f,.0f,.0f }, /* 3 lobed Blackman-Bessel */
+    { Sinc,      4.0f,  1.0f, 0.0f, 0.0f }, /* 4 lobed Blackman-Sinc   */
+    { Kaiser,    1.0f,  1.0f, 0.0f, 0.0f }, /* Kaiser, sq-root windowing */
+    { Welsh,     1.0f,  1.0f, 0.0f, 0.0f }, /* Welsh, Parabolic windowing */
+    { CubicBC,   2.0f,  2.0f, 1.0f, 0.0f }, /* Parzen, B-Spline windowing */
+    { Lagrange,  2.0f,  1.0f, 0.0f, 0.0f }, /* Lagrangian Filter */
+    { Bohman,    1.0f,  1.0f, 0.0f, 0.0f }, /* Bohman, 2*Cosine windowing */
+    { Triangle,  1.0f,  1.0f, 0.0f, 0.0f }  /* Bartlett, Triangle windowing */
+  };
+  /*
+    The known zero crossings of the Bessel() or the Jinc(x*PI) function
+    Found by using
+      http://cose.math.bas.bg/webMathematica/webComputing/BesselZeros.jsp
+    for Jv-function with v=1,  then dividing X-roots by PI (tabled below)
+  */
+  static MagickRealType
+    bessel_zeros[16] =
+    {
+      1.21966989126651f,
+      2.23313059438153f,
+      3.23831548416624f,
+      4.24106286379607f,
+      5.24276437687019f,
+      6.24392168986449f,
+      7.24475986871996f,
+      8.24539491395205f,
+      9.24589268494948f,
+      10.2462933487549f,
+      11.2466227948779f,
+      12.2468984611381f,
+      13.2471325221811f,
+      14.2473337358069f,
+      15.2475085630373f,
+      16.247661874701f
+   };
+
+  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;
+
+
+  /* Filter blur -- scaling both filter and support window */
+  resize_filter->blur = blur;
+  artifact=GetImageArtifact(image,"filter:blur");
+  if (artifact != (const char *) NULL)
+    resize_filter->blur = atof(artifact);
+  if ( resize_filter->blur < MagickEpsilon )
+    resize_filter->blur = (MagickRealType) MagickEpsilon;
+
+  /* Modifications for Cylindrical filter use */
+  if ( cylindrical != MagickFalse && filter != SincFilter ) {
+    /* promote 1D Sinc Filter to a 2D Bessel filter */
+    if ( filter_type == SincFilter )
+      filter_type = BesselFilter;
+    /* Prompote Lanczos (Sinc-Sinc) to Lanczos (Bessel-Bessel) */
+    else if ( filter_type == LanczosFilter ) {
+      filter_type = BesselFilter;
+      window_type = BesselFilter;
+    }
+   /* Blur other filters appropriatally correct cylindrical usage */
+    else if ( filter_type == GaussianFilter )
+      /* Gaussian is scaled by  4*ln(2) and not 4*sqrt(2/MagickPI)
+         - according to Paul Heckbert's paper on EWA resampling */
+      resize_filter->blur *= 2.0*log(2.0)/sqrt(2.0/MagickPI);
+    else if ( filter_type != BesselFilter )
+      /* filters with a 1.0 zero root crossing by the first bessel_zero */
+      resize_filter->blur *= bessel_zeros[0];
+  }
+
+  /* Override Filter Selection */
+  artifact=GetImageArtifact(image,"filter:filter");
+  if (artifact != (const char *) NULL) {
+    /* raw filter request - no window function */
+    filter_artifact=ParseMagickOption(MagickFilterOptions,
+         MagickFalse,artifact);
+    if ( UndefinedFilter < filter_artifact &&
+             filter_artifact < SentinelFilter ) {
+      filter_type = (FilterTypes) filter_artifact;
+      window_type = BoxFilter;
+    }
+    /* Lanczos is nor a real filter but a self windowing Sinc/Bessel */
+    if ( filter_artifact == LanczosFilter ) {
+      filter_type = (cylindrical!=MagickFalse) ? BesselFilter : LanczosFilter;
+      window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
+    }
+    /* Filter overwide with a specific window function? */
+    artifact=GetImageArtifact(image,"filter:window");
+    if (artifact != (const char *) NULL) {
+      filter_artifact=ParseMagickOption(MagickFilterOptions,
+            MagickFalse,artifact);
+      if ( UndefinedFilter < filter_artifact &&
+               filter_artifact < SentinelFilter ) {
+        if ( filter_artifact != LanczosFilter )
+          window_type = (FilterTypes) filter_artifact;
+        else
+          window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
+      }
+    }
+  }
+  else {
+    /* window specified, but no filter function?  Assume Sinc/Bessel */
+    artifact=GetImageArtifact(image,"filter:window");
+    if (artifact != (const char *) NULL) {
+      filter_artifact=ParseMagickOption(MagickFilterOptions,MagickFalse,
+        artifact);
+      if ( UndefinedFilter < filter_artifact &&
+               filter_artifact < SentinelFilter ) {
+        filter_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
+        if ( filter_artifact != LanczosFilter )
+          window_type = (FilterTypes) filter_artifact;
+        else
+          window_type = filter_type;
+      }
+    }
+  }
+
+  resize_filter->filter   = filters[filter_type].function;
+  resize_filter->support  = filters[filter_type].support;
+  resize_filter->window   = filters[window_type].function;
+  resize_filter->scale    = filters[window_type].scale;
+  resize_filter->signature=MagickSignature;
+
+  /* Filter support overrides */
+  artifact=GetImageArtifact(image,"filter:lobes");
+  if (artifact != (const char *) NULL) {
+    long lobes = atol(artifact);
+    if ( lobes < 1  ) lobes = 1;
+    resize_filter->support = (MagickRealType) lobes;
+    if ( filter_type == BesselFilter ) {
+      if ( lobes > 16 ) lobes = 16;
+      resize_filter->support = bessel_zeros[lobes-1];
+    }
+  }
+  artifact=GetImageArtifact(image,"filter:support");
+  if (artifact != (const char *) NULL)
+    resize_filter->support = fabs(atof(artifact));
+
+  /* Scale windowing function separatally to the support 'clipping' window
+     that calling operator is planning to actually use. - Expert Use Only
+  */
+  resize_filter->window_support = resize_filter->support;
+  artifact=GetImageArtifact(image,"filter:win-support");
+  if (artifact != (const char *) NULL)
+    resize_filter->window_support = fabs(atof(artifact));
+
+  /* Set Cubic Spline B,C values, calculate Cubic coefficents */
+  B=0.0;
+  C=0.0;
+  if ( filters[filter_type].function == CubicBC
+       || filters[window_type].function == CubicBC ) {
+    if ( filters[filter_type].function == CubicBC ) {
+      B=filters[filter_type].B;
+      C=filters[filter_type].C;
+    }
+    else 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=atof(artifact);
+      C=(1.0-B)/2.0; /* Calculate C as if it is a Keys cubic filter */
+      artifact=GetImageArtifact(image,"filter:c");
+      if (artifact != (const char *) NULL)
+        C=atof(artifact);
+    }
+    else {
+      artifact=GetImageArtifact(image,"filter:c");
+      if (artifact != (const char *) NULL) {
+        C=atof(artifact);
+        B=1.0-2.0*C;  /* Calculate B as if it is a Keys cubic filter */
+      }
+    }
+    /* Convert B,C values into Cubic Coefficents - See CubicBC() */
+    resize_filter->cubic[0]=(  6.0 -2.0*B       )/6.0;
+    resize_filter->cubic[1]=0.0;
+    resize_filter->cubic[2]=(-18.0+12.0*B+ 6.0*C)/6.0;
+    resize_filter->cubic[3]=( 12.0- 9.0*B- 6.0*C)/6.0;
+    resize_filter->cubic[4]=(       8.0*B+24.0*C)/6.0;
+    resize_filter->cubic[5]=(     -12.0*B-48.0*C)/6.0;
+    resize_filter->cubic[6]=(       6.0*B+30.0*C)/6.0;
+    resize_filter->cubic[7]=(     - 1.0*B- 6.0*C)/6.0;
+  }
+  artifact=GetImageArtifact(image,"filter:verbose");
+  if (artifact != (const char *) NULL)
+    {
+      double
+        support,
+        x;
+
+      /*
+        Output filter graph -- for graphing filter result.
+      */
+      support=GetResizeFilterSupport(resize_filter);
+      (void) printf("# support = %lg\n",support);
+      for (x=0.0; x <= support; x+=0.01f)
+        (void) printf("%5.2lf\t%lf\n",x,GetResizeFilterWeight(resize_filter,x));
+      (void) printf("%5.2lf\t%lf\n",support,0.0);
+    }
+  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 unsigned long columns,const unsigned long 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 unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
+{
+#define AdaptiveResizeImageTag  "Resize/Image"
+
+  Image
+    *resize_image;
+
+  long
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  MagickPixelPacket
+    pixel;
+
+  PointInfo
+    offset;
+
+  ResampleFilter
+    *resample_filter;
+
+  CacheView
+    *resize_view;
+
+  /*
+    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);
+    }
+  GetMagickPixelPacket(image,&pixel);
+  resample_filter=AcquireResampleFilter(image,exception);
+  if (image->interpolate == UndefinedInterpolatePixel)
+    (void) SetResampleFilterInterpolateMethod(resample_filter,
+      MeshInterpolatePixel);
+  resize_view=AcquireCacheView(resize_image);
+  for (y=0; y < (long) resize_image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict resize_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
+    offset.y=((MagickRealType) y*image->rows/resize_image->rows);
+    for (x=0; x < (long) resize_image->columns; x++)
+    {
+      offset.x=((MagickRealType) x*image->columns/resize_image->columns);
+      (void) ResamplePixelColor(resample_filter,offset.x-0.5,offset.y-0.5,
+        &pixel);
+      SetPixelPacket(resize_image,&pixel,q,resize_indexes+x);
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,AdaptiveResizeImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  resample_filter=DestroyResampleFilter(resample_filter);
+  resize_view=DestroyCacheView(resize_view);
+  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:
+%
+%    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 long
+    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 long
+    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 long
+    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 long
+    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 AcquireResizeFilter 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
+    blur,
+    scale;
+
+  /*
+    Windowing function - scale the weighting filter by this amount.
+  */
+  assert(resize_filter != (ResizeFilter *) NULL);
+  assert(resize_filter->signature == MagickSignature);
+  blur=fabs(x)/resize_filter->blur;  /* X offset with blur scaling */
+  if ((resize_filter->window_support < MagickEpsilon) ||
+      (resize_filter->window == Box))
+    scale=1.0;  /* Point/Box Filter -- avoid division by zero */
+  else
+    {
+      scale=resize_filter->scale/resize_filter->window_support;
+      scale=resize_filter->window(blur*scale,resize_filter);
+    }
+  return(scale*resize_filter->filter(blur,resize_filter));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+
+  unsigned long
+    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=(unsigned long) (x_resolution*image->columns/
+    (image->x_resolution == 0.0 ? 72.0 : image->x_resolution)+0.5);
+  height=(unsigned long) (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 unsigned long columns,const unsigned long 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 unsigned long columns,const unsigned long rows,
+  const double delta_x,const double rigidity,ExceptionInfo *exception)
+{
+#define LiquidRescaleImageTag  "Rescale/Image"
+
+  const char
+    *map;
+
+  guchar
+    *packet;
+
+  Image
+    *rescale_image;
+
+  int
+    x,
+    y;
+
+  LqrCarver
+    *carver;
+
+  LqrRetVal
+    lqr_status;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    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(ZoomImage(image,columns,rows,exception));
+  if ((columns >= (2*image->columns)) || (rows >= (2*image->rows)))
+    {
+      Image
+        *resize_image;
+
+      unsigned long
+        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);
+  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);
+    }
+  GetMagickPixelPacket(rescale_image,&pixel);
+  (void) lqr_carver_scan_reset(carver);
+  while (lqr_carver_scan(carver,&x,&y,&packet) != 0)
+  {
+    register IndexPacket
+      *__restrict rescale_indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueAuthenticPixels(rescale_image,x,y,1,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    rescale_indexes=GetAuthenticIndexQueue(rescale_image);
+    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.opacity=QuantumRange*(packet[3]/255.0);
+      }
+    else
+      {
+        pixel.index=QuantumRange*(packet[3]/255.0);
+        if (image->matte == MagickFalse)
+          pixel.opacity=QuantumRange*(packet[4]/255.0);
+      }
+    SetPixelPacket(rescale_image,&pixel,q,rescale_indexes);
+    if (SyncAuthenticPixels(rescale_image,exception) == MagickFalse)
+      break;
+  }
+  /*
+    Relinquish resources.
+  */
+  lqr_carver_destroy(carver);
+  return(rescale_image);
+}
+#else
+MagickExport Image *LiquidRescaleImage(const Image *image,
+  const unsigned long magick_unused(columns),
+  const unsigned long 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 unsigned long columns,
+%        const unsigned long 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;
+
+  long
+    pixel;
+} ContributionInfo;
+
+static ContributionInfo **DestroyContributionThreadSet(
+  ContributionInfo **contribution)
+{
+  register long
+    i;
+
+  assert(contribution != (ContributionInfo **) NULL);
+  for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
+    if (contribution[i] != (ContributionInfo *) NULL)
+      contribution[i]=(ContributionInfo *) RelinquishMagickMemory(
+        contribution[i]);
+  contribution=(ContributionInfo **) RelinquishAlignedMemory(contribution);
+  return(contribution);
+}
+
+static ContributionInfo **AcquireContributionThreadSet(const size_t count)
+{
+  register long
+    i;
+
+  ContributionInfo
+    **contribution;
+
+  unsigned long
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  contribution=(ContributionInfo **) AcquireAlignedMemory(number_threads,
+    sizeof(*contribution));
+  if (contribution == (ContributionInfo **) NULL)
+    return((ContributionInfo **) NULL);
+  (void) ResetMagickMemory(contribution,0,number_threads*sizeof(*contribution));
+  for (i=0; i < (long) 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 *quantum,ExceptionInfo *exception)
+{
+#define ResizeImageTag  "Resize/Image"
+
+  ClassType
+    storage_class;
+
+  ContributionInfo
+    **contributions;
+
+  long
+    x;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    scale,
+    support;
+
+  CacheView
+    *image_view,
+    *resize_view;
+
+  /*
+    Apply filter to resize horizontally from image to resize image.
+  */
+  scale=MagickMax(1.0/x_factor,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 < (long) resize_image->columns; x++)
+  {
+    long
+      n,
+      start,
+      stop;
+
+    MagickRealType
+      center,
+      density;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register ContributionInfo
+      *__restrict contribution;
+
+    register IndexPacket
+      *__restrict resize_indexes;
+
+    register long
+      y;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    center=(MagickRealType) (x+0.5)/x_factor;
+    start=(long) (MagickMax(center-support-MagickEpsilon,0.0)+0.5);
+    stop=(long) (MagickMin(center+support,(double) image->columns)+0.5);
+    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 long
+          i;
+
+        /*
+          Normalize.
+        */
+        density=1.0/density;
+        for (i=0; i < n; i++)
+          contribution[i].weight*=density;
+      }
+    p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,
+      (unsigned long) (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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
+    for (y=0; y < (long) resize_image->rows; y++)
+    {
+      long
+        j;
+
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        alpha;
+
+      register long
+        i;
+
+      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*(p+j)->red;
+            pixel.green+=alpha*(p+j)->green;
+            pixel.blue+=alpha*(p+j)->blue;
+            pixel.opacity+=alpha*(p+j)->opacity;
+          }
+          q->red=RoundToQuantum(pixel.red);
+          q->green=RoundToQuantum(pixel.green);
+          q->blue=RoundToQuantum(pixel.blue);
+          q->opacity=RoundToQuantum(pixel.opacity);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            {
+              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.index+=alpha*indexes[j];
+              }
+              resize_indexes[y]=(IndexPacket) RoundToQuantum(pixel.index);
+            }
+        }
+      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*((MagickRealType)
+              QuantumRange-(p+j)->opacity);
+            pixel.red+=alpha*(p+j)->red;
+            pixel.green+=alpha*(p+j)->green;
+            pixel.blue+=alpha*(p+j)->blue;
+            pixel.opacity+=contribution[i].weight*(p+j)->opacity;
+            gamma+=alpha;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          q->red=RoundToQuantum(gamma*pixel.red);
+          q->green=RoundToQuantum(gamma*pixel.green);
+          q->blue=RoundToQuantum(gamma*pixel.blue);
+          q->opacity=RoundToQuantum(pixel.opacity);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            {
+              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*((MagickRealType)
+                  QuantumRange-(p+j)->opacity);
+                gamma+=alpha;
+              }
+              resize_indexes[y]=(IndexPacket) RoundToQuantum(gamma*pixel.index);
+            }
+        }
+      if ((resize_image->storage_class == PseudoClass) &&
+          (image->storage_class == PseudoClass))
+        {
+          i=(long) (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);
+          resize_indexes[y]=indexes[j];
+        }
+      q++;
+    }
+    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,(*quantum)++,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 *quantum,ExceptionInfo *exception)
+{
+  ClassType
+    storage_class;
+
+  ContributionInfo
+    **contributions;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    scale,
+    support;
+
+  CacheView
+    *image_view,
+    *resize_view;
+
+  /*
+    Apply filter to resize vertically from image to resize_image.
+  */
+  scale=MagickMax(1.0/y_factor,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 < (long) resize_image->rows; y++)
+  {
+    long
+      n,
+      start,
+      stop;
+
+    MagickRealType
+      center,
+      density;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register ContributionInfo
+      *__restrict contribution;
+
+    register IndexPacket
+      *__restrict resize_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    center=(MagickRealType) (y+0.5)/y_factor;
+    start=(long) (MagickMax(center-support-MagickEpsilon,0.0)+0.5);
+    stop=(long) (MagickMin(center+support,(double) image->rows)+0.5);
+    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 long
+          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,(unsigned long) (contribution[n-1].pixel-
+      contribution[0].pixel+1),exception);
+    q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
+    for (x=0; x < (long) resize_image->columns; x++)
+    {
+      long
+        j;
+
+      MagickPixelPacket
+        pixel;
+
+      MagickRealType
+        alpha;
+
+      register long
+        i;
+
+      pixel=zero;
+      if (image->matte == MagickFalse)
+        {
+          for (i=0; i < n; i++)
+          {
+            j=(long) ((contribution[i].pixel-contribution[0].pixel)*
+              image->columns+x);
+            alpha=contribution[i].weight;
+            pixel.red+=alpha*(p+j)->red;
+            pixel.green+=alpha*(p+j)->green;
+            pixel.blue+=alpha*(p+j)->blue;
+            pixel.opacity+=alpha*(p+j)->opacity;
+          }
+          q->red=RoundToQuantum(pixel.red);
+          q->green=RoundToQuantum(pixel.green);
+          q->blue=RoundToQuantum(pixel.blue);
+          q->opacity=RoundToQuantum(pixel.opacity);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            {
+              for (i=0; i < n; i++)
+              {
+                j=(long) ((contribution[i].pixel-contribution[0].pixel)*
+                  image->columns+x);
+                alpha=contribution[i].weight;
+                pixel.index+=alpha*indexes[j];
+              }
+              resize_indexes[x]=(IndexPacket) RoundToQuantum(pixel.index);
+            }
+        }
+      else
+        {
+          MagickRealType
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < n; i++)
+          {
+            j=(long) ((contribution[i].pixel-contribution[0].pixel)*
+              image->columns+x);
+            alpha=contribution[i].weight*QuantumScale*((MagickRealType)
+              QuantumRange-(p+j)->opacity);
+            pixel.red+=alpha*(p+j)->red;
+            pixel.green+=alpha*(p+j)->green;
+            pixel.blue+=alpha*(p+j)->blue;
+            pixel.opacity+=contribution[i].weight*(p+j)->opacity;
+            gamma+=alpha;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          q->red=RoundToQuantum(gamma*pixel.red);
+          q->green=RoundToQuantum(gamma*pixel.green);
+          q->blue=RoundToQuantum(gamma*pixel.blue);
+          q->opacity=RoundToQuantum(pixel.opacity);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            {
+              for (i=0; i < n; i++)
+              {
+                j=(long) ((contribution[i].pixel-contribution[0].pixel)*
+                  image->columns+x);
+                alpha=contribution[i].weight*QuantumScale*((MagickRealType)
+                  QuantumRange-(p+j)->opacity);
+                pixel.index+=alpha*indexes[j];
+              }
+              resize_indexes[x]=(IndexPacket) RoundToQuantum(gamma*pixel.index);
+            }
+        }
+      if ((resize_image->storage_class == PseudoClass) &&
+          (image->storage_class == PseudoClass))
+        {
+          i=(long) (MagickMin(MagickMax(center,(double) start),(double) stop-
+            1.0)+0.5);
+          j=(long) ((contribution[i-start].pixel-contribution[0].pixel)*
+            image->columns+x);
+          resize_indexes[x]=indexes[j];
+        }
+      q++;
+    }
+    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,(*quantum)++,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 unsigned long columns,
+  const unsigned long rows,const FilterTypes filter,const double blur,
+  ExceptionInfo *exception)
+{
+#define WorkLoadFactor  0.265
+
+  FilterTypes
+    filter_type;
+
+  Image
+    *filter_image,
+    *resize_image;
+
+  MagickRealType
+    x_factor,
+    y_factor;
+
+  MagickSizeType
+    span;
+
+  MagickStatusType
+    status;
+
+  ResizeFilter
+    *resize_filter;
+
+  MagickOffsetType
+    quantum;
+
+  /*
+    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.
+  */
+  quantum=0;
+  if ((x_factor*y_factor) > WorkLoadFactor)
+    {
+      span=(MagickSizeType) (filter_image->columns+rows);
+      status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
+        &quantum,exception);
+      status&=VerticalFilter(resize_filter,filter_image,resize_image,y_factor,
+        span,&quantum,exception);
+    }
+  else
+    {
+      span=(MagickSizeType) (filter_image->rows+columns);
+      status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
+        &quantum,exception);
+      status&=HorizontalFilter(resize_filter,filter_image,resize_image,x_factor,
+        span,&quantum,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 unsigned long columns,
+%        const unsigned long 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 unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+#define SampleImageTag  "Sample/Image"
+
+  Image
+    *sample_image;
+
+  long
+    progress,
+    *x_offset,
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    x;
+
+  CacheView
+    *image_view,
+    *sample_view;
+
+  /*
+    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=(long *) AcquireQuantumMemory((size_t) sample_image->columns,
+    sizeof(*x_offset));
+  if (x_offset == (long *) NULL)
+    {
+      sample_image=DestroyImage(sample_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  for (x=0; x < (long) sample_image->columns; x++)
+    x_offset[x]=(long) (((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) shared(progress,status)
+#endif
+  for (y=0; y < (long) sample_image->rows; y++)
+  {
+    long
+      y_offset;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict sample_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    y_offset=(long) (((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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    sample_indexes=GetCacheViewAuthenticIndexQueue(sample_view);
+    /*
+      Sample each column.
+    */
+    for (x=0; x < (long) sample_image->columns; x++)
+      *q++=p[x_offset[x]];
+    if ((image->storage_class == PseudoClass) ||
+        (image->colorspace == CMYKColorspace))
+      for (x=0; x < (long) sample_image->columns; x++)
+        sample_indexes[x]=indexes[x_offset[x]];
+    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=(long *) 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 unsigned long columns,
+%        const unsigned long 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 unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+#define ScaleImageTag  "Scale/Image"
+
+  Image
+    *scale_image;
+
+  long
+    number_rows,
+    y;
+
+  MagickBooleanType
+    next_column,
+    next_row,
+    proceed;
+
+  MagickPixelPacket
+    pixel,
+    *scale_scanline,
+    *scanline,
+    *x_vector,
+    *y_vector,
+    zero;
+
+  MagickRealType
+    alpha,
+    gamma;
+
+  PointInfo
+    scale,
+    span;
+
+  register long
+    i;
+
+  /*
+    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=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
+    sizeof(*x_vector));
+  scanline=x_vector;
+  if (image->rows != scale_image->rows)
+    scanline=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
+      sizeof(*scanline));
+  scale_scanline=(MagickPixelPacket *) AcquireQuantumMemory((size_t)
+    scale_image->columns,sizeof(*scale_scanline));
+  y_vector=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
+    sizeof(*y_vector));
+  if ((scanline == (MagickPixelPacket *) NULL) ||
+      (scale_scanline == (MagickPixelPacket *) NULL) ||
+      (x_vector == (MagickPixelPacket *) NULL) ||
+      (y_vector == (MagickPixelPacket *) 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));
+  GetMagickPixelPacket(image,&pixel);
+  (void) ResetMagickMemory(&zero,0,sizeof(zero));
+  i=0;
+  for (y=0; y < (long) scale_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict scale_indexes;
+
+    register long
+      x;
+
+    register MagickPixelPacket
+      *__restrict s,
+      *__restrict t;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueAuthenticPixels(scale_image,0,y,scale_image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    scale_indexes=GetAuthenticIndexQueue(scale_image);
+    if (scale_image->rows == image->rows)
+      {
+        /*
+          Read a new scanline.
+        */
+        p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(image);
+        for (x=0; x < (long) image->columns; x++)
+        {
+          x_vector[x].red=(MagickRealType) p->red;
+          x_vector[x].green=(MagickRealType) p->green;
+          x_vector[x].blue=(MagickRealType) p->blue;
+          if (image->matte != MagickFalse)
+            x_vector[x].opacity=(MagickRealType) p->opacity;
+          if (indexes != (IndexPacket *) NULL)
+            x_vector[x].index=(MagickRealType) indexes[x];
+          p++;
+        }
+      }
+    else
+      {
+        /*
+          Scale Y direction.
+        */
+        while (scale.y < span.y)
+        {
+          if ((next_row != MagickFalse) && (number_rows < (long) image->rows))
+            {
+              /*
+                Read a new scanline.
+              */
+              p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
+              if (p == (const PixelPacket *) NULL)
+                break;
+              indexes=GetVirtualIndexQueue(image);
+              for (x=0; x < (long) image->columns; x++)
+              {
+                x_vector[x].red=(MagickRealType) p->red;
+                x_vector[x].green=(MagickRealType) p->green;
+                x_vector[x].blue=(MagickRealType) p->blue;
+                if (image->matte != MagickFalse)
+                  x_vector[x].opacity=(MagickRealType) p->opacity;
+                if (indexes != (IndexPacket *) NULL)
+                  x_vector[x].index=(MagickRealType) indexes[x];
+                p++;
+              }
+              number_rows++;
+            }
+          for (x=0; x < (long) 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->matte != MagickFalse)
+              y_vector[x].opacity+=scale.y*x_vector[x].opacity;
+            if (scale_indexes != (IndexPacket *) NULL)
+              y_vector[x].index+=scale.y*x_vector[x].index;
+          }
+          span.y-=scale.y;
+          scale.y=(double) scale_image->rows/(double) image->rows;
+          next_row=MagickTrue;
+        }
+        if ((next_row != MagickFalse) && (number_rows < (long) image->rows))
+          {
+            /*
+              Read a new scanline.
+            */
+            p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(image);
+            for (x=0; x < (long) image->columns; x++)
+            {
+              x_vector[x].red=(MagickRealType) p->red;
+              x_vector[x].green=(MagickRealType) p->green;
+              x_vector[x].blue=(MagickRealType) p->blue;
+              if (image->matte != MagickFalse)
+                x_vector[x].opacity=(MagickRealType) p->opacity;
+              if (indexes != (IndexPacket *) NULL)
+                x_vector[x].index=(MagickRealType) indexes[x];
+              p++;
+            }
+            number_rows++;
+            next_row=MagickFalse;
+          }
+        s=scanline;
+        for (x=0; x < (long) 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->matte != MagickFalse)
+            pixel.opacity=y_vector[x].opacity+span.y*x_vector[x].opacity;
+          if (scale_indexes != (IndexPacket *) NULL)
+            pixel.index=y_vector[x].index+span.y*x_vector[x].index;
+          s->red=pixel.red;
+          s->green=pixel.green;
+          s->blue=pixel.blue;
+          if (scale_image->matte != MagickFalse)
+            s->opacity=pixel.opacity;
+          if (scale_indexes != (IndexPacket *) NULL)
+            s->index=pixel.index;
+          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 < (long) scale_image->columns; x++)
+        {
+          q->red=RoundToQuantum(s->red);
+          q->green=RoundToQuantum(s->green);
+          q->blue=RoundToQuantum(s->blue);
+          if (scale_image->matte != MagickFalse)
+            q->opacity=RoundToQuantum(s->opacity);
+          if (scale_indexes != (IndexPacket *) NULL)
+            scale_indexes[x]=(IndexPacket) RoundToQuantum(s->index);
+          q++;
+          s++;
+        }
+      }
+    else
+      {
+        /*
+          Scale X direction.
+        */
+        pixel=zero;
+        next_column=MagickFalse;
+        span.x=1.0;
+        s=scanline;
+        t=scale_scanline;
+        for (x=0; x < (long) 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 (image->matte != MagickFalse)
+              pixel.opacity+=span.x*s->opacity;
+            if (scale_indexes != (IndexPacket *) NULL)
+              pixel.index+=span.x*s->index;
+            t->red=pixel.red;
+            t->green=pixel.green;
+            t->blue=pixel.blue;
+            if (scale_image->matte != MagickFalse)
+              t->opacity=pixel.opacity;
+            if (scale_indexes != (IndexPacket *) NULL)
+              t->index=pixel.index;
+            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->matte != MagickFalse)
+              pixel.opacity+=scale.x*s->opacity;
+            if (scale_indexes != (IndexPacket *) NULL)
+              pixel.index+=scale.x*s->index;
+            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->matte != MagickFalse)
+            pixel.opacity+=span.x*s->opacity;
+          if (scale_indexes != (IndexPacket *) NULL)
+            pixel.index+=span.x*s->index;
+        }
+      if ((next_column == MagickFalse) &&
+          ((long) (t-scale_scanline) < (long) scale_image->columns))
+        {
+          t->red=pixel.red;
+          t->green=pixel.green;
+          t->blue=pixel.blue;
+          if (scale_image->matte != MagickFalse)
+            t->opacity=pixel.opacity;
+          if (scale_indexes != (IndexPacket *) NULL)
+            t->index=pixel.index;
+        }
+      /*
+        Transfer scanline to scaled image.
+      */
+      t=scale_scanline;
+      for (x=0; x < (long) scale_image->columns; x++)
+      {
+        alpha=1.0;
+        if (image->matte != MagickFalse)
+          alpha=(MagickRealType) (QuantumScale*(QuantumRange-t->opacity));
+        gamma=1.0/(fabs((double) alpha) <= MagickEpsilon ? 1.0 : alpha);
+        q->red=RoundToQuantum(gamma*t->red);
+        q->green=RoundToQuantum(gamma*t->green);
+        q->blue=RoundToQuantum(gamma*t->blue);
+        if (scale_image->matte != MagickFalse)
+          q->opacity=RoundToQuantum(t->opacity);
+        if (scale_indexes != (IndexPacket *) NULL)
+          scale_indexes[x]=(IndexPacket) RoundToQuantum(gamma*t->index);
+        t++;
+        q++;
+      }
+    }
+    if (SyncAuthenticPixels(scale_image,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,ScaleImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  /*
+    Free allocated memory.
+  */
+  y_vector=(MagickPixelPacket *) RelinquishMagickMemory(y_vector);
+  scale_scanline=(MagickPixelPacket *) RelinquishMagickMemory(scale_scanline);
+  if (scale_image->rows != image->rows)
+    scanline=(MagickPixelPacket *) RelinquishMagickMemory(scanline);
+  x_vector=(MagickPixelPacket *) RelinquishMagickMemory(x_vector);
+  scale_image->type=image->type;
+  return(scale_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t R e s i z e F i l t e r S u p p o r t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetResizeFilterSupport() specifies which IR filter to use to window
+%
+%  The format of the SetResizeFilterSupport method is:
+%
+%      void SetResizeFilterSupport(ResizeFilter *resize_filter,
+%        const MagickRealType support)
+%
+%  A description of each parameter follows:
+%
+%    o resize_filter: the resize filter.
+%
+%    o support: the filter spport radius.
+%
+*/
+MagickExport void SetResizeFilterSupport(ResizeFilter *resize_filter,
+  const MagickRealType support)
+{
+  assert(resize_filter != (ResizeFilter *) NULL);
+  assert(resize_filter->signature == MagickSignature);
+  resize_filter->support=support;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long columns,
+%        const unsigned long 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 unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
+{
+#define SampleFactor  5
+
+  char
+    value[MaxTextExtent];
+
+  const char
+    *name;
+
+  Image
+    *thumbnail_image;
+
+  MagickRealType
+    x_factor,
+    y_factor;
+
+  struct stat
+    attributes;
+
+  unsigned long
+    version;
+
+  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=ZoomImage(image,columns,rows,exception);
+  else
+    if (((SampleFactor*columns) < 128) || ((SampleFactor*rows) < 128))
+      thumbnail_image=ZoomImage(image,columns,rows,exception);
+    else
+      {
+        Image
+          *sample_image;
+
+        sample_image=SampleImage(image,SampleFactor*columns,SampleFactor*rows,
+          exception);
+        if (sample_image == (Image *) NULL)
+          return((Image *) NULL);
+        thumbnail_image=ZoomImage(sample_image,columns,rows,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))
+     {
+       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) FormatMagickString(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) FormatMagickString(value,MaxTextExtent,"%ld",(long)
+        attributes.st_mtime);
+      (void) SetImageProperty(thumbnail_image,"Thumb::MTime",value);
+    }
+  (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
+    attributes.st_mtime);
+  (void) FormatMagickSize(GetBlobSize(image),value);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Size",value);
+  (void) FormatMagickString(value,MaxTextExtent,"image/%s",image->magick);
+  LocaleLower(value);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Mimetype",value);
+  (void) SetImageProperty(thumbnail_image,"software",
+    GetMagickVersion(&version));
+  (void) FormatMagickString(value,MaxTextExtent,"%lu",image->magick_columns);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Image::Width",value);
+  (void) FormatMagickString(value,MaxTextExtent,"%lu",image->magick_rows);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Image::height",value);
+  (void) FormatMagickString(value,MaxTextExtent,"%lu",
+    GetImageListLength(image));
+  (void) SetImageProperty(thumbnail_image,"Thumb::Document::Pages",value);
+  return(thumbnail_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Z o o m I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ZoomImage() creates a new image that is a scaled size of an existing one.
+%  It allocates the memory necessary for the new Image structure and returns a
+%  pointer to the new image.  The Point filter gives fast pixel replication,
+%  Triangle is equivalent to bi-linear interpolation, and Mitchel giver slower,
+%  very high-quality results.  See Graphic Gems III for details on this
+%  algorithm.
+%
+%  The filter member of the Image structure specifies which image filter to
+%  use. Blur specifies the blur factor where > 1 is blurry, < 1 is sharp.
+%
+%  The format of the ZoomImage method is:
+%
+%      Image *ZoomImage(const Image *image,const unsigned long columns,
+%        const unsigned long rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: An integer that specifies the number of columns in the zoom
+%      image.
+%
+%    o rows: An integer that specifies the number of rows in the scaled
+%      image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ZoomImage(const Image *image,const unsigned long columns,
+  const unsigned long rows,ExceptionInfo *exception)
+{
+  Image
+    *zoom_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);
+  zoom_image=ResizeImage(image,columns,rows,image->filter,image->blur,
+    exception);
+  return(zoom_image);
+}
diff --git a/magick/resize.h b/magick/resize.h
new file mode 100644
index 0000000..b0eb78e
--- /dev/null
+++ b/magick/resize.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2009 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 unsigned long,const unsigned long,
+    ExceptionInfo *),
+  *LiquidRescaleImage(const Image *,const unsigned long,const unsigned long,
+    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 unsigned long,const unsigned long,
+    const FilterTypes,const double,ExceptionInfo *),
+  *SampleImage(const Image *,const unsigned long,const unsigned long,
+    ExceptionInfo *),
+  *ScaleImage(const Image *,const unsigned long,const unsigned long,
+    ExceptionInfo *),
+  *ThumbnailImage(const Image *,const unsigned long,const unsigned long,
+    ExceptionInfo *),
+  *ZoomImage(const Image *,const unsigned long,const unsigned long,
+    ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/resource.c b/magick/resource.c
new file mode 100644
index 0000000..5b45c62
--- /dev/null
+++ b/magick/resource.c
@@ -0,0 +1,1085 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/log.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/policy.h"
+#include "magick/random_.h"
+#include "magick/registry.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/string_.h"
+#include "magick/splay-tree.h"
+#include "magick/thread-private.h"
+#include "magick/token.h"
+#include "magick/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(2048)*1024*1024,
+    MagickULLConstant(1536)*1024*1024,
+    MagickULLConstant(8192)*1024*1024,
+    MagickResourceInfinity,
+    MagickULLConstant(768),
+    MagickULLConstant(8),
+    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,resource_request);
+  AcquireSemaphoreInfo(&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,
+        resource_current);
+      (void) FormatMagickSize(resource_info.area_limit,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,
+        resource_current);
+      (void) FormatMagickSize(resource_info.memory_limit,
+        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,
+        resource_current);
+      (void) FormatMagickSize(resource_info.map_limit,
+        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,
+        resource_current);
+      (void) FormatMagickSize(resource_info.disk_limit,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,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
+        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,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
+        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,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
+        resource_limit);
+      break;
+    }
+    default:
+      break;
+  }
+  RelinquishSemaphoreInfo(resource_semaphore);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
+    MagickOptionToMnemonic(MagickResourceOptions,(long) type),resource_request,
+    resource_current,resource_limit);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A s y n c h r o n o u s D e s t r o y M a g i c k R e s o u r c e s       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AsynchronousDestroyMagickResources() destroys the resource environment.
+%  It differs from DestroyMagickResources() in that it can be called from a
+%  asynchronous signal handler.
+%
+%  The format of the DestroyMagickResources() method is:
+%
+%      DestroyMagickResources(void)
+%
+*/
+MagickExport void AsynchronousDestroyMagickResources(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);
+  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(__WINDOWS__) || 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) FormatMagickString(path,MaxTextExtent,"%smagick-XXXXXXXX",directory);
+  else
+    (void) FormatMagickString(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
+
+  char
+    *resource;
+
+  int
+    c,
+    file;
+
+  register char
+    *p;
+
+  register long
+    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 < TMP_MAX; i++)
+  {
+    /*
+      Get temporary pathname.
+    */
+    (void) GetPathTemplate(path);
+#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,8);
+    p=path+strlen(path)-8;
+    datum=GetStringInfoDatum(key);
+    for (i=0; i < 8; 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);
+  AcquireSemaphoreInfo(&resource_semaphore);
+  if (temporary_resources == (SplayTreeInfo *) NULL)
+    temporary_resources=NewSplayTree(CompareSplayTreeString,
+      RelinquishMagickMemory,DestroyTemporaryResources);
+  RelinquishSemaphoreInfo(resource_semaphore);
+  resource=ConstantString(path);
+  (void) AddValueToSplayTree(temporary_resources,resource,resource);
+  return(file);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M a g i c k R e s o u r c e s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagickResources() destroys the resource environment.
+%
+%  The format of the DestroyMagickResources() method is:
+%
+%      DestroyMagickResources(void)
+%
+*/
+MagickExport void DestroyMagickResources(void)
+{
+  AcquireSemaphoreInfo(&resource_semaphore);
+  if (temporary_resources != (SplayTreeInfo *) NULL)
+    temporary_resources=DestroySplayTree(temporary_resources);
+  if (random_info != (RandomInfo *) NULL)
+    random_info=DestroyRandomInfo(random_info);
+  RelinquishSemaphoreInfo(resource_semaphore);
+  DestroySemaphoreInfo(&resource_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+  AcquireSemaphoreInfo(&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;
+  }
+  RelinquishSemaphoreInfo(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                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickResource() returns the specified resource limit.
+%
+%  The format of the GetMagickResourceLimit() method is:
+%
+%      unsigned long 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;
+  AcquireSemaphoreInfo(&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;
+  }
+  RelinquishSemaphoreInfo(resource_semaphore);
+  return(resource);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e M a g i c k R e s o u r c e s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeMagickResources() initializes the resource environment.
+%
+%  The format of the InitializeMagickResources() method is:
+%
+%      InitializeMagickResources(void)
+%
+*/
+
+static inline unsigned long MagickMax(const unsigned long x,
+  const unsigned long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline MagickSizeType StringToSizeType(const char *string,
+  const double interval)
+{
+  double
+    value;
+
+  value=StringToDouble(string,interval);
+  if (value >= (double) MagickULLConstant(~0))
+    return(MagickULLConstant(~0));
+  return((MagickSizeType) value);
+}
+
+MagickExport void InitializeMagickResources(void)
+{
+  char
+    *limit;
+
+  long
+    files,
+    pages,
+    pagesize;
+
+  MagickSizeType
+    memory;
+
+  /*
+    Set Magick resource limits.
+  */
+  pagesize=(-1);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+  pagesize=sysconf(_SC_PAGESIZE);
+#elif defined(MAGICKCORE_HAVE_GETPAGESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
+  pagesize=getpagesize();
+#endif
+  pages=(-1);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
+  pages=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,2UL*memory);
+  (void) SetMagickResourceLimit(MemoryResource,3UL*memory/2UL);
+  (void) SetMagickResourceLimit(MapResource,4UL*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=sysconf(_SC_OPEN_MAX);
+#elif defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
+  files=getdtablesize();
+#endif
+  (void) SetMagickResourceLimit(FileResource,MagickMax((unsigned long)
+    (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)
+    {
+      SetOpenMPMaximumThreads((unsigned long) atol(limit));
+      (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);
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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;
+  AcquireSemaphoreInfo(&resource_semaphore);
+  (void) FormatMagickSize(resource_info.area_limit,area_limit);
+  (void) FormatMagickSize(resource_info.memory_limit,memory_limit);
+  (void) FormatMagickSize(resource_info.map_limit,map_limit);
+  (void) FormatMagickSize(resource_info.disk_limit,disk_limit);
+  (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
+  if (resource_info.time_limit != MagickResourceInfinity)
+    (void) FormatMagickString(time_limit,MaxTextExtent,"%lu",(unsigned long)
+      resource_info.time_limit);
+  (void) fprintf(file,"File       Area     Memory        Map"
+    "       Disk  Thread       Time\n");
+  (void) fprintf(file,"-----------------------------------------------------"
+    "--------------\n");
+  (void) fprintf(file,"%4lu  %9s  %9s  %9s  %9s  %6lu  %9s\n",(unsigned long)
+    resource_info.file_limit,area_limit,memory_limit,map_limit,disk_limit,
+    (unsigned long) resource_info.thread_limit,time_limit);
+  (void) fflush(file);
+  RelinquishSemaphoreInfo(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,resource_request);
+  AcquireSemaphoreInfo(&resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource_info.area=(MagickOffsetType) size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.area,
+        resource_current);
+      (void) FormatMagickSize(resource_info.area_limit,resource_limit);
+      break;
+    }
+    case MemoryResource:
+    {
+      resource_info.memory-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.memory,
+        resource_current);
+      (void) FormatMagickSize(resource_info.memory_limit,resource_limit);
+      break;
+    }
+    case MapResource:
+    {
+      resource_info.map-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.map,
+        resource_current);
+      (void) FormatMagickSize(resource_info.map_limit,resource_limit);
+      break;
+    }
+    case DiskResource:
+    {
+      resource_info.disk-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.disk,
+        resource_current);
+      (void) FormatMagickSize(resource_info.disk_limit,resource_limit);
+      break;
+    }
+    case FileResource:
+    {
+      resource_info.file-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.file,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
+        resource_limit);
+      break;
+    }
+    case ThreadResource:
+    {
+      resource_info.thread-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
+        resource_limit);
+      break;
+    }
+    case TimeResource:
+    {
+      resource_info.time-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.time,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
+        resource_limit);
+      break;
+    }
+    default:
+      break;
+  }
+  RelinquishSemaphoreInfo(resource_semaphore);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
+    MagickOptionToMnemonic(MagickResourceOptions,(long) 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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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.
+%
+*/
+MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
+  const MagickSizeType limit)
+{
+  AcquireSemaphoreInfo(&resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource_info.area_limit=limit;
+      break;
+    }
+    case MemoryResource:
+    {
+      resource_info.memory_limit=limit;
+      break;
+    }
+    case MapResource:
+    {
+      resource_info.map_limit=limit;
+      break;
+    }
+    case DiskResource:
+    {
+      resource_info.disk_limit=limit;
+      break;
+    }
+    case FileResource:
+    {
+      resource_info.file_limit=limit;
+      break;
+    }
+    case ThreadResource:
+    {
+      SetOpenMPMaximumThreads((unsigned long) limit);
+      resource_info.thread_limit=GetOpenMPMaximumThreads();
+      break;
+    }
+    case TimeResource:
+    {
+      resource_info.time_limit=limit;
+      break;
+    }
+    default:
+      break;
+  }
+  RelinquishSemaphoreInfo(resource_semaphore);
+  return(MagickTrue);
+}
diff --git a/magick/resource_.h b/magick/resource_.h
new file mode 100644
index 0000000..7bac7e9
--- /dev/null
+++ b/magick/resource_.h
@@ -0,0 +1,62 @@
+/*
+  Copyright 1999-2009 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
+} ResourceType;
+
+#define MagickResourceInfinity  MagickULLConstant(~0)
+
+extern MagickExport int
+  AcquireUniqueFileResource(char *);
+
+extern MagickExport MagickBooleanType
+  AcquireMagickResource(const ResourceType,const MagickSizeType),
+  RelinquishUniqueFileResource(const char *),
+  ListMagickResourceInfo(FILE *,ExceptionInfo *),
+  SetMagickResourceLimit(const ResourceType,const MagickSizeType);
+
+extern MagickExport MagickSizeType
+  GetMagickResource(const ResourceType),
+  GetMagickResourceLimit(const ResourceType);
+
+extern MagickExport void
+  AsynchronousDestroyMagickResources(void),
+  DestroyMagickResources(void),
+  InitializeMagickResources(void),
+  RelinquishMagickResource(const ResourceType,const MagickSizeType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/segment.c b/magick/segment.c
new file mode 100644
index 0000000..4ea18ba
--- /dev/null
+++ b/magick/segment.c
@@ -0,0 +1,1912 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/color.h"
+#include "magick/colorspace.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/segment.h"
+#include "magick/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;
+
+  long
+    index,
+    left,
+    right;
+} ExtentPacket;
+
+typedef struct _Cluster
+{
+  struct _Cluster
+    *next;
+
+  ExtentPacket
+    red,
+    green,
+    blue;
+
+  long
+    count,
+    id;
+} Cluster;
+
+typedef struct _IntervalTree
+{
+  MagickRealType
+    tau;
+
+  long
+    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 long *,const double,const double,const double,
+    const double,short *);
+
+static long
+  DefineRegion(const short *,ExtentPacket *);
+
+static void
+  InitializeHistogram(const Image *,long **,ExceptionInfo *),
+  ScaleSpace(const long *,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"
+
+  Cluster
+    *cluster,
+    *head,
+    *last_cluster,
+    *next_cluster;
+
+  ExceptionInfo
+    *exception;
+
+  ExtentPacket
+    blue,
+    green,
+    red;
+
+  long
+    count,
+    progress,
+    y;
+
+  MagickRealType
+    *free_squares;
+
+  MagickStatusType
+    status;
+
+  register long
+    i;
+
+  register MagickRealType
+    *squares;
+
+  unsigned long
+    number_clusters;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *p;
+
+    register long
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        if (((long) ScaleQuantumToChar(p->red) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->red) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->green) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->green) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->blue) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->blue) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Count this pixel.
+            */
+            count++;
+            cluster->red.center+=(MagickRealType) ScaleQuantumToChar(p->red);
+            cluster->green.center+=(MagickRealType)
+              ScaleQuantumToChar(p->green);
+            cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(p->blue);
+            cluster->count++;
+            break;
+          }
+      p++;
+    }
+    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=(unsigned long) count;
+  if (verbose != MagickFalse)
+    {
+      /*
+        Print cluster statistics.
+      */
+      (void) fprintf(stdout,"Fuzzy C-means Statistics\n");
+      (void) fprintf(stdout,"===================\n\n");
+      (void) fprintf(stdout,"\tCluster Threshold = %g\n",cluster_threshold);
+      (void) fprintf(stdout,"\tWeighting Exponent = %g\n",weighting_exponent);
+      (void) fprintf(stdout,"\tTotal Number of Clusters = %lu\n\n",
+        number_clusters);
+      /*
+        Print the total number of points per cluster.
+      */
+      (void) fprintf(stdout,"\n\nNumber of Vectors Per Cluster\n");
+      (void) fprintf(stdout,"=============================\n\n");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        (void) fprintf(stdout,"Cluster #%ld = %ld\n",cluster->id,
+          cluster->count);
+      /*
+        Print the cluster extents.
+      */
+      (void) fprintf(stdout,
+        "\n\n\nCluster Extents:        (Vector Size: %d)\n",MaxDimension);
+      (void) fprintf(stdout,"================");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        (void) fprintf(stdout,"\n\nCluster #%ld\n\n",cluster->id);
+        (void) fprintf(stdout,"%ld-%ld  %ld-%ld  %ld-%ld\n",cluster->red.left,
+          cluster->red.right,cluster->green.left,cluster->green.right,
+          cluster->blue.left,cluster->blue.right);
+      }
+      /*
+        Print the cluster center values.
+      */
+      (void) fprintf(stdout,
+        "\n\n\nCluster Center Values:        (Vector Size: %d)\n",MaxDimension);
+      (void) fprintf(stdout,"=====================");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        (void) fprintf(stdout,"\n\nCluster #%ld\n\n",cluster->id);
+        (void) fprintf(stdout,"%g  %g  %g\n",(double) cluster->red.center,
+          (double) cluster->green.center,(double) cluster->blue.center);
+      }
+      (void) fprintf(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,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    Cluster
+      *cluster;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      indexes[x]=(IndexPacket) 0;
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        if (((long) ScaleQuantumToChar(q->red) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(q->red) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(q->green) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(q->green) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(q->blue) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(q->blue) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Classify this pixel.
+            */
+            indexes[x]=(IndexPacket) cluster->id;
+            break;
+          }
+      }
+      if (cluster == (Cluster *) NULL)
+        {
+          MagickRealType
+            distance_squared,
+            local_minima,
+            numerator,
+            ratio,
+            sum;
+
+          register long
+            j,
+            k;
+
+          /*
+            Compute fuzzy membership.
+          */
+          local_minima=0.0;
+          for (j=0; j < (long) image->colors; j++)
+          {
+            sum=0.0;
+            p=image->colormap+j;
+            distance_squared=squares[(long) ScaleQuantumToChar(q->red)-
+              (long) ScaleQuantumToChar(p->red)]+
+              squares[(long) ScaleQuantumToChar(q->green)-
+              (long) ScaleQuantumToChar(p->green)]+
+              squares[(long) ScaleQuantumToChar(q->blue)-
+              (long) ScaleQuantumToChar(p->blue)];
+            numerator=distance_squared;
+            for (k=0; k < (long) image->colors; k++)
+            {
+              p=image->colormap+k;
+              distance_squared=squares[(long) ScaleQuantumToChar(q->red)-
+                (long) ScaleQuantumToChar(p->red)]+
+                squares[(long) ScaleQuantumToChar(q->green)-
+                (long) ScaleQuantumToChar(p->green)]+
+                squares[(long) ScaleQuantumToChar(q->blue)-
+                (long) 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;
+                indexes[x]=(IndexPacket) j;
+              }
+          }
+        }
+      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_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 unsigned long number_crossings)
+%
+%  A description of each parameter follows.
+%
+%    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
+%
+%    o number_crossings: This unsigned long specifies the number of elements
+%      in the zero_crossing array.
+%
+*/
+
+static inline long MagickAbsoluteValue(const long x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+static inline long MagickMax(const long x,const long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline long MagickMin(const long x,const long y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
+  const unsigned long number_crossings)
+{
+  long
+    center,
+    correct,
+    count,
+    left,
+    right;
+
+  register long
+    i,
+    j,
+    k,
+    l;
+
+  /*
+    Consolidate zero crossings.
+  */
+  for (i=(long) 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=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:
+%
+%      long 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 long 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 long
+    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,
+%        MagickPixelPacket *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,
+  MagickPixelPacket *pixel,ExceptionInfo *exception)
+{
+  Cluster
+    *background,
+    *cluster,
+    *object,
+    *head,
+    *last_cluster,
+    *next_cluster;
+
+  ExtentPacket
+    blue,
+    green,
+    red;
+
+  long
+    count,
+    *histogram[MaxDimension],
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  MagickRealType
+    threshold;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i,
+    x;
+
+  short
+    *extrema[MaxDimension];
+
+  /*
+    Allocate histogram and extrema.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetMagickPixelPacket(image,pixel);
+  for (i=0; i < MaxDimension; i++)
+  {
+    histogram[i]=(long *) AcquireQuantumMemory(256UL,sizeof(**histogram));
+    extrema[i]=(short *) AcquireQuantumMemory(256UL,sizeof(**histogram));
+    if ((histogram[i] == (long *) NULL) || (extrema[i] == (short *) NULL))
+      {
+        for (i-- ; i >= 0; i--)
+        {
+          extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+          histogram[i]=(long *) 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 < (long) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        if (((long) ScaleQuantumToChar(p->red) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->red) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->green) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->green) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->blue) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((long) ScaleQuantumToChar(p->blue) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Count this pixel.
+            */
+            count++;
+            cluster->red.center+=(MagickRealType)
+              ScaleQuantumToChar(p->red);
+            cluster->green.center+=(MagickRealType)
+              ScaleQuantumToChar(p->green);
+            cluster->blue.center+=(MagickRealType)
+              ScaleQuantumToChar(p->blue);
+            cluster->count++;
+            break;
+          }
+      p++;
+    }
+    proceed=SetImageProgress(image,SegmentImageTag,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]=(long *) 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,long **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,long **histogram,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  register const PixelPacket
+    *p;
+
+  register long
+    i,
+    x;
+
+  /*
+    Initialize histogram.
+  */
+  for (i=0; i <= 255; i++)
+  {
+    histogram[Red][i]=0;
+    histogram[Green][i]=0;
+    histogram[Blue][i]=0;
+  }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      histogram[Red][(long) ScaleQuantumToChar(p->red)]++;
+      histogram[Green][(long) ScaleQuantumToChar(p->green)]++;
+      histogram[Blue][(long) ScaleQuantumToChar(p->blue)]++;
+      p++;
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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,long *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 unsigned long specifies the number of elements
+%      in the zero_crossing array.
+%
+*/
+
+static void InitializeList(IntervalTree **list,long *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 long
+        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 unsigned long number_crossings)
+{
+  IntervalTree
+    *head,
+    **list,
+    *node,
+    *root;
+
+  long
+    j,
+    k,
+    left,
+    number_nodes;
+
+  register long
+    i;
+
+  /*
+    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 < (long) 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 long *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,long *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 long *histogram,const double max_tau,
+  const double min_tau,const double delta_tau,const double smooth_threshold,
+  short *extrema)
+{
+  IntervalTree
+    **list,
+    *node,
+    *root;
+
+  long
+    index,
+    j,
+    k,
+    number_nodes;
+
+  MagickRealType
+    average_tau,
+    *derivative,
+    *second_derivative,
+    tau,
+    value;
+
+  register long
+    i,
+    x;
+
+  MagickBooleanType
+    peak;
+
+  unsigned long
+    count,
+    number_crossings;
+
+  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=(unsigned long) ((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 < (long) 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=(unsigned long) 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 <= (long) 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 <= (long) 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 long *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 long *histogram,const MagickRealType tau,
+  MagickRealType *scale_histogram)
+{
+  MagickRealType
+    alpha,
+    beta,
+    *gamma,
+    sum;
+
+  register long
+    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)
+{
+  long
+    *histogram[MaxDimension];
+
+  MagickBooleanType
+    status;
+
+  register long
+    i;
+
+  short
+    *extrema[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]=(long *) AcquireQuantumMemory(256,sizeof(**histogram));
+    extrema[i]=(short *) AcquireQuantumMemory(256,sizeof(**extrema));
+    if ((histogram[i] == (long *) NULL) || (extrema[i] == (short *) NULL))
+      {
+        for (i-- ; i >= 0; i--)
+        {
+          extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+          histogram[i]=(long *) 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]=(long *) 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)
+{
+  long
+    parity;
+
+  register long
+    i;
+
+  /*
+    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/magick/segment.h b/magick/segment.h
new file mode 100644
index 0000000..0be37b6
--- /dev/null
+++ b/magick/segment.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2009 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,
+    MagickPixelPacket *,ExceptionInfo *),
+  SegmentImage(Image *,const ColorspaceType,const MagickBooleanType,
+    const double,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/semaphore.c b/magick/semaphore.c
new file mode 100644
index 0000000..e666f20
--- /dev/null
+++ b/magick/semaphore.c
@@ -0,0 +1,442 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/thread_.h"
+#include "magick/thread-private.h"
+
+/*
+  Struct declaractions.
+*/
+struct SemaphoreInfo
+{
+  MagickMutexType
+    mutex;
+
+  MagickThreadType
+    id;
+
+  long
+    reference_count;
+
+  unsigned long
+    signature;
+};
+
+/*
+  Static declaractions.
+*/
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+static pthread_mutex_t
+  semaphore_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+static LONG
+  semaphore_mutex = 0;
+#else
+static long
+  semaphore_mutex = 0;
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 defined(MAGICKCORE_HAVE_PTHREAD)
+  if (pthread_mutex_lock(&semaphore_mutex) != 0)
+    (void) fprintf(stderr,"pthread_mutex_lock failed %s\n",
+      GetExceptionMessage(errno));
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  while (InterlockedCompareExchange(&semaphore_mutex,1L,0L) != 0)
+    Sleep(10);
+#endif
+  if (*semaphore_info == (SemaphoreInfo *) NULL)
+    *semaphore_info=AllocateSemaphoreInfo();
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  if (pthread_mutex_unlock(&semaphore_mutex) != 0)
+    (void) fprintf(stderr,"pthread_mutex_unlock failed %s\n",
+      GetExceptionMessage(errno));
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  InterlockedExchange(&semaphore_mutex,0L);
+#endif
+  (void) LockSemaphoreInfo(*semaphore_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 *) AcquireAlignedMemory(1,
+    sizeof(SemaphoreInfo));
+  if (semaphore_info == (SemaphoreInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(semaphore_info,0,sizeof(SemaphoreInfo));
+  /*
+    Initialize the semaphore.
+  */
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  {
+    int
+      status;
+
+    pthread_mutexattr_t
+      mutex_info;
+
+    status=pthread_mutexattr_init(&mutex_info);
+    if (status != 0)
+      {
+        semaphore_info=(SemaphoreInfo *) RelinquishAlignedMemory(
+          semaphore_info);
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+      }
+    status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
+    (void) pthread_mutexattr_destroy(&mutex_info);
+    if (status != 0)
+      {
+        semaphore_info=(SemaphoreInfo *) RelinquishAlignedMemory(
+          semaphore_info);
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+      }
+  }
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  InitializeCriticalSection(&semaphore_info->mutex);
+#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                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroySemaphore() destroys the semaphore environment.
+%
+%  The format of the DestroySemaphore method is:
+%
+%      DestroySemaphore(void)
+%
+*/
+MagickExport void DestroySemaphore(void)
+{
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  if (pthread_mutex_destroy(&semaphore_mutex) != 0)
+    (void) fprintf(stderr,"pthread_mutex_destroy failed %s\n",
+      GetExceptionMessage(errno));
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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);
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  (void) pthread_mutex_lock(&semaphore_mutex);
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  while (InterlockedCompareExchange(&semaphore_mutex,1L,0L) != 0)
+    Sleep(10);
+#endif
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  (void) pthread_mutex_destroy(&(*semaphore_info)->mutex);
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  DeleteCriticalSection(&(*semaphore_info)->mutex);
+#endif
+  (*semaphore_info)->signature=(~MagickSignature);
+  *semaphore_info=(SemaphoreInfo *) RelinquishAlignedMemory(*semaphore_info);
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  (void) pthread_mutex_unlock(&semaphore_mutex);
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  InterlockedExchange(&semaphore_mutex,0L);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n i t i a l i z e S e m a p h o r e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeSemaphore() initializes the semaphore environment.
+%
+%  The format of the InitializeSemaphore method is:
+%
+%      InitializeSemaphore(void)
+%
+*/
+MagickExport void InitializeSemaphore(void)
+{
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      MagickBooleanType LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport MagickBooleanType LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo *) NULL);
+  assert(semaphore_info->signature == MagickSignature);
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  {
+    int
+      status;
+
+    status=pthread_mutex_lock(&semaphore_info->mutex);
+    if (status != 0)
+      return(MagickFalse);
+#if defined(MAGICKCORE_DEBUG)
+    {
+      if ((semaphore_info->reference_count > 0) &&
+          (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
+        {
+          (void) fprintf(stderr,"Warning: unexpected recursive lock!\n");
+          (void) fflush(stderr);
+        }
+    }
+#endif
+  }
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  {
+    EnterCriticalSection(&semaphore_info->mutex);
+#if defined(MAGICKCORE_DEBUG)
+    {
+      if ((semaphore_info->reference_count > 0) &&
+          (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
+        {
+          (void) fprintf(stderr,"Warning: unexpected recursive lock!\n");
+          (void) fflush(stderr);
+        }
+    }
+#endif
+  }
+#endif
+  semaphore_info->id=GetMagickThreadId();
+  semaphore_info->reference_count++;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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);
+  (void) UnlockSemaphoreInfo(semaphore_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      MagickBooleanType UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport MagickBooleanType 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) fprintf(stderr,"Warning: semaphore lock already unlocked!\n");
+      (void) fflush(stderr);
+      return(MagickFalse);
+    }
+  semaphore_info->reference_count--;
+#endif
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  {
+    int
+      status;
+
+    status=pthread_mutex_unlock(&semaphore_info->mutex);
+    if (status != 0)
+      {
+        semaphore_info->reference_count++;
+        return(MagickFalse);
+      }
+  }
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  LeaveCriticalSection(&semaphore_info->mutex);
+#endif
+  return(MagickTrue);
+}
diff --git a/magick/semaphore.h b/magick/semaphore.h
new file mode 100644
index 0000000..acd4d48
--- /dev/null
+++ b/magick/semaphore.h
@@ -0,0 +1,46 @@
+/*
+  Copyright 1999-2009 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
+  LockSemaphoreInfo(SemaphoreInfo *),
+  UnlockSemaphoreInfo(SemaphoreInfo *);
+
+extern MagickExport SemaphoreInfo
+  *AllocateSemaphoreInfo(void);
+
+extern MagickExport void
+  AcquireSemaphoreInfo(SemaphoreInfo **),
+  DestroySemaphore(void),
+  DestroySemaphoreInfo(SemaphoreInfo **),
+  InitializeSemaphore(void),
+  RelinquishSemaphoreInfo(SemaphoreInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/shear.c b/magick/shear.c
new file mode 100644
index 0000000..788610c
--- /dev/null
+++ b/magick/shear.c
@@ -0,0 +1,2110 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/artifact.h"
+#include "magick/blob-private.h"
+#include "magick/cache-private.h"
+#include "magick/color-private.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/decorate.h"
+#include "magick/distort.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/memory_.h"
+#include "magick/list.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel-private.h"
+#include "magick/quantum.h"
+#include "magick/resource_.h"
+#include "magick/shear.h"
+#include "magick/statistic.h"
+#include "magick/threshold.h"
+#include "magick/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:
+%
+%      Image *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 inline void 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 long
+    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=(long) (min.x+0.5);
+  geometry.y=(long) (min.y+0.5);
+  geometry.width=(unsigned long) ((long) (max.x+0.5)-(long) (min.x+0.5));
+  geometry.height=(unsigned long) ((long) (max.y+0.5)-(long) (min.y+0.5));
+  page=(*image)->page;
+  (void) ParseAbsoluteGeometry("0x0+0+0",&(*image)->page);
+  crop_image=CropImage(*image,&geometry,exception);
+  (*image)->page=page;
+  if (crop_image != (Image *) NULL)
+    {
+      crop_image->page=page;
+      *image=DestroyImage(*image);
+      *image=crop_image;
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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;
+
+  unsigned long
+    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)
+{
+  long
+    y;
+
+  register long
+    x;
+
+  ssize_t
+    count;
+
+  unsigned short
+    value;
+
+  if (radon_info->type != DiskCache)
+    {
+      (void) ResetMagickMemory(radon_info->cells,0,(size_t) radon_info->length);
+      return(MagickTrue);
+    }
+  value=0;
+  (void) MagickSeek(radon_info->file,0,SEEK_SET);
+  for (y=0; y < (long) radon_info->height; y++)
+  {
+    for (x=0; x < (long) 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 < (long) radon_info->width)
+      break;
+  }
+  return(y < (long) radon_info->height ? MagickFalse : MagickTrue);
+}
+
+static RadonInfo *AcquireRadonInfo(const Image *image,const unsigned long width,
+  const unsigned long 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 off_t 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 (MagickSeek(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),(off_t) (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 off_t 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 (MagickSeek(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),(off_t) (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 long x,const long y)
+{
+  off_t
+    i;
+
+  unsigned short
+    value;
+
+  i=(off_t) 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 long x,const long y,const unsigned short value)
+{
+  off_t
+    i;
+
+  ssize_t
+    count;
+
+  i=(off_t) 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),(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 long sign,unsigned long *projection)
+{
+  RadonInfo
+    *swap;
+
+  register long
+    x;
+
+  register RadonInfo
+    *p,
+    *q;
+
+  unsigned long
+    step;
+
+  p=source_cells;
+  q=destination_cells;
+  for (step=1; step < p->width; step*=2)
+  {
+    for (x=0; x < (long) p->width; x+=2*step)
+    {
+      long
+        y;
+
+      register long
+        i;
+
+      unsigned short
+        cell;
+
+      for (i=0; i < (long) step; i++)
+      {
+        for (y=0; y < (long) (p->height-i-1); y++)
+        {
+          cell=GetRadonCell(p,x+i,y);
+          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+step,y+i));
+          (void) SetRadonCell(q,x+2*i+1,y,cell+GetRadonCell(p,x+i+step,y+i+1));
+        }
+        for ( ; y < (long) (p->height-i); y++)
+        {
+          cell=GetRadonCell(p,x+i,y);
+          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+step,y+i));
+          (void) SetRadonCell(q,x+2*i+1,y,cell);
+        }
+        for ( ; y < (long) 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
+#endif
+  for (x=0; x < (long) p->width; x++)
+  {
+    register long
+      y;
+
+    unsigned long
+      sum;
+
+    sum=0;
+    for (y=0; y < (long) (p->height-1); y++)
+    {
+      long
+        delta;
+
+      delta=GetRadonCell(p,x,y)-(long) GetRadonCell(p,x,y+1);
+      sum+=delta*delta;
+    }
+    projection[p->width+sign*x-1]=sum;
+  }
+}
+
+static MagickBooleanType RadonTransform(const Image *image,
+  const double threshold,unsigned long *projection,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  RadonInfo
+    *destination_cells,
+    *source_cells;
+
+  register long
+    i;
+
+  unsigned char
+    byte;
+
+  unsigned long
+    count,
+    width;
+
+  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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      i,
+      x;
+
+    unsigned long
+      bit,
+      byte;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    bit=0;
+    byte=0;
+    i=(long) (image->columns+7)/8;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      byte<<=1;
+      if (((MagickRealType) p->red < threshold) ||
+          ((MagickRealType) p->green < threshold) ||
+          ((MagickRealType) p->blue < threshold))
+        byte|=0x01;
+      bit++;
+      if (bit == 8)
+        {
+          (void) SetRadonCell(source_cells,--i,y,bits[byte]);
+          bit=0;
+          byte=0;
+        }
+      p++;
+    }
+    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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      i,
+      x;
+
+    unsigned long
+      bit,
+      byte;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    bit=0;
+    byte=0;
+    i=0;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      byte<<=1;
+      if (((MagickRealType) p->red < threshold) ||
+          ((MagickRealType) p->green < threshold) ||
+          ((MagickRealType) p->blue < threshold))
+        byte|=0x01;
+      bit++;
+      if (bit == 8)
+        {
+          (void) SetRadonCell(source_cells,i++,y,bits[byte]);
+          bit=0;
+          byte=0;
+        }
+      p++;
+    }
+    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 long offset,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  long
+    y;
+
+  MagickPixelPacket
+    background;
+
+  MagickRealType
+    count;
+
+  /*
+    Compute average background color.
+  */
+  if (offset <= 0)
+    return;
+  GetMagickPixelPacket(image,&background);
+  count=0.0;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    if ((y >= offset) && (y < ((long) image->rows-offset)))
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      continue;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((x >= offset) && (x < ((long) image->columns-offset)))
+        continue;
+      background.red+=QuantumScale*p->red;
+      background.green+=QuantumScale*p->green;
+      background.blue+=QuantumScale*p->blue;
+      background.opacity+=QuantumScale*p->opacity;
+      count++;
+      p++;
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  image->background_color.red=RoundToQuantum((MagickRealType) QuantumRange*
+    background.red/count);
+  image->background_color.green=RoundToQuantum((MagickRealType) QuantumRange*
+    background.green/count);
+  image->background_color.blue=RoundToQuantum((MagickRealType) QuantumRange*
+    background.blue/count);
+  image->background_color.opacity=RoundToQuantum((MagickRealType) QuantumRange*
+    background.opacity/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;
+
+  long
+    skew;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    geometry;
+
+  register long
+    i;
+
+  unsigned long
+    max_projection,
+    *projection,
+    width;
+
+  /*
+    Compute deskew angle.
+  */
+  for (width=1; width < ((image->columns+7)/8); width<<=1) ;
+  projection=(unsigned long *) AcquireQuantumMemory((size_t) (2*width-1),
+    sizeof(*projection));
+  if (projection == (unsigned long *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  status=RadonTransform(image,threshold,projection,exception);
+  if (status == MagickFalse)
+    {
+      projection=(unsigned long *) RelinquishMagickMemory(projection);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  max_projection=0;
+  skew=0;
+  for (i=0; i < (long) (2*width-1); i++)
+  {
+    if (projection[i] > max_projection)
+      {
+        skew=i-(long) width+1;
+        max_projection=projection[i];
+      }
+  }
+  projection=(unsigned long *) 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,atol(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=MedianFilterImage(deskew_image,0.0,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: "
+      "%lux%lu%+ld%+ld",geometry.width,geometry.height,geometry.x,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,unsigned long 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,unsigned long rotations,
+  ExceptionInfo *exception)
+{
+#define TileHeight  128
+#define TileWidth  128
+#define RotateImageTag  "Rotate/Image"
+
+  CacheView
+    *image_view,
+    *rotate_view;
+
+  Image
+    *rotate_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    page;
+
+  /*
+    Initialize rotated image attributes.
+  */
+  assert(image != (Image *) NULL);
+  page=image->page;
+  rotations%=4;
+  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.
+      */
+      for (y=0; y < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const IndexPacket
+          *__restrict indexes;
+
+        register const PixelPacket
+          *__restrict p;
+
+        register IndexPacket
+          *__restrict rotate_indexes;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+        q=QueueCacheViewAuthenticPixels(rotate_view,0,y,rotate_image->columns,1,
+          exception);
+        if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewVirtualIndexQueue(image_view);
+        rotate_indexes=GetCacheViewAuthenticIndexQueue(rotate_view);
+        (void) CopyMagickMemory(q,p,image->columns*sizeof(*p));
+        if ((indexes != (IndexPacket *) NULL) &&
+            (rotate_indexes != (IndexPacket *) NULL))
+          (void) CopyMagickMemory(rotate_indexes,indexes,image->columns*
+            sizeof(*indexes));
+        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;
+          }
+      }
+      break;
+    }
+    case 1:
+    {
+      long
+        tile_y;
+
+      /*
+        Rotate 90 degrees.
+      */
+      for (tile_y=0; tile_y < (long) image->rows; tile_y+=TileHeight)
+      {
+        register long
+          tile_x;
+
+        if (status == MagickFalse)
+          continue;
+        for (tile_x=0; tile_x < (long) image->columns; tile_x+=TileWidth)
+        {
+          MagickBooleanType
+            sync;
+
+          register const IndexPacket
+            *__restrict indexes;
+
+          register const PixelPacket
+            *__restrict p;
+
+          register IndexPacket
+            *__restrict rotate_indexes;
+
+          register long
+            y;
+
+          register PixelPacket
+            *__restrict q;
+
+          unsigned long
+            tile_height,
+            tile_width;
+
+          tile_width=TileWidth;
+          if ((tile_x+TileWidth) > (long) image->columns)
+            tile_width=(unsigned long) (TileWidth-(tile_x+TileWidth-
+              image->columns));
+          tile_height=TileHeight;
+          if ((tile_y+TileHeight) > (long) image->rows)
+            tile_height=(unsigned long) (TileHeight-(tile_y+TileHeight-
+              image->rows));
+          p=GetCacheViewVirtualPixels(image_view,tile_x,tile_y,tile_width,
+            tile_height,exception);
+          if (p == (const PixelPacket *) NULL)
+            {
+              status=MagickFalse;
+              break;
+            }
+          indexes=GetCacheViewVirtualIndexQueue(image_view);
+          for (y=0; y < (long) tile_width; y++)
+          {
+            register const PixelPacket
+              *__restrict tile_pixels;
+
+            register long
+              x;
+
+            q=QueueCacheViewAuthenticPixels(rotate_view,(long)
+              rotate_image->columns-(tile_y+tile_height),y+tile_x,tile_height,
+              1,exception);
+            if (q == (PixelPacket *) NULL)
+              {
+                status=MagickFalse;
+                break;
+              }
+            tile_pixels=p+(tile_height-1)*tile_width+y;
+            for (x=0; x < (long) tile_height; x++)
+            {
+              *q++=(*tile_pixels);
+              tile_pixels-=tile_width;
+            }
+            rotate_indexes=GetCacheViewAuthenticIndexQueue(rotate_view);
+            if ((indexes != (IndexPacket *) NULL) &&
+                (rotate_indexes != (IndexPacket *) NULL))
+              {
+                register const IndexPacket
+                  *__restrict tile_indexes;
+
+                tile_indexes=indexes+(tile_height-1)*tile_width+y;
+                for (x=0; x < (long) tile_height; x++)
+                {
+                  *rotate_indexes++=(*tile_indexes);
+                  tile_indexes-=tile_width;
+                }
+              }
+            sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
+            if (sync == MagickFalse)
+              status=MagickFalse;
+          }
+        }
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,RotateImageTag,progress+=TileHeight,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      Swap(page.width,page.height);
+      Swap(page.x,page.y);
+      if (page.width != 0)
+        page.x=(long) (page.width-rotate_image->columns-page.x);
+      break;
+    }
+    case 2:
+    {
+      /*
+        Rotate 180 degrees.
+      */
+      for (y=0; y < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const IndexPacket
+          *__restrict indexes;
+
+        register const PixelPacket
+          *__restrict p;
+
+        register IndexPacket
+          *__restrict rotate_indexes;
+
+        register long
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
+          exception);
+        q=QueueCacheViewAuthenticPixels(rotate_view,0,(long) (image->rows-
+          y-1),image->columns,1,exception);
+        if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewVirtualIndexQueue(image_view);
+        rotate_indexes=GetCacheViewAuthenticIndexQueue(rotate_view);
+        q+=image->columns;
+        for (x=0; x < (long) image->columns; x++)
+          *--q=(*p++);
+        if ((indexes != (IndexPacket *) NULL) &&
+            (rotate_indexes != (IndexPacket *) NULL))
+          for (x=0; x < (long) image->columns; x++)
+            rotate_indexes[image->columns-x-1]=indexes[x];
+        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=(long) (page.width-rotate_image->columns-page.x);
+      if (page.height != 0)
+        page.y=(long) (page.height-rotate_image->rows-page.y);
+      break;
+    }
+    case 3:
+    {
+      long
+        tile_y;
+
+      /*
+        Rotate 270 degrees.
+      */
+      for (tile_y=0; tile_y < (long) image->rows; tile_y+=TileHeight)
+      {
+        register long
+          tile_x;
+
+        if (status == MagickFalse)
+          continue;
+        for (tile_x=0; tile_x < (long) image->columns; tile_x+=TileWidth)
+        {
+          MagickBooleanType
+            sync;
+
+          register const IndexPacket
+            *__restrict indexes;
+
+          register const PixelPacket
+            *__restrict p;
+
+          register IndexPacket
+            *__restrict rotate_indexes;
+
+          register long
+            y;
+
+          register PixelPacket
+            *__restrict q;
+
+          unsigned long
+            tile_height,
+            tile_width;
+
+          tile_width=TileWidth;
+          if ((tile_x+TileWidth) > (long) image->columns)
+            tile_width=(unsigned long) (TileWidth-(tile_x+TileWidth-
+              image->columns));
+          tile_height=TileHeight;
+          if ((tile_y+TileHeight) > (long) image->rows)
+            tile_height=(unsigned long) (TileHeight-(tile_y+TileHeight-
+              image->rows));
+          p=GetCacheViewVirtualPixels(image_view,tile_x,tile_y,tile_width,
+            tile_height,exception);
+          if (p == (const PixelPacket *) NULL)
+            {
+              status=MagickFalse;
+              break;
+            }
+          indexes=GetCacheViewVirtualIndexQueue(image_view);
+          for (y=0; y < (long) tile_width; y++)
+          {
+            register const PixelPacket
+              *__restrict tile_pixels;
+
+            register long
+              x;
+
+            q=QueueCacheViewAuthenticPixels(rotate_view,tile_y,(long)
+              y+rotate_image->rows-(tile_x+tile_width),tile_height,1,exception);
+            if (q == (PixelPacket *) NULL)
+              {
+                status=MagickFalse;
+                break;
+              }
+            tile_pixels=p+(tile_width-1)-y;
+            for (x=0; x < (long) tile_height; x++)
+            {
+              *q++=(*tile_pixels);
+              tile_pixels+=tile_width;
+            }
+            rotate_indexes=GetCacheViewAuthenticIndexQueue(rotate_view);
+            if ((indexes != (IndexPacket *) NULL) &&
+                (rotate_indexes != (IndexPacket *) NULL))
+              {
+                register const IndexPacket
+                  *__restrict tile_indexes;
+
+                tile_indexes=indexes+(tile_width-1)-y;
+                for (x=0; x < (long) tile_height; x++)
+                {
+                  *rotate_indexes++=(*tile_indexes);
+                  tile_indexes+=tile_width;
+                }
+              }
+            sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
+            if (sync == MagickFalse)
+              status=MagickFalse;
+          }
+        }
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,RotateImageTag,progress+=TileHeight,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      Swap(page.width,page.height);
+      Swap(page.x,page.y);
+      if (page.height != 0)
+        page.y=(long) (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 unsigned long width,const unsigned long height,
+%        const long x_offset,const long y_offset)
+%
+%  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.
+%
+*/
+static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
+  const unsigned long width,const unsigned long height,const long x_offset,
+  const long y_offset)
+{
+#define XShearImageTag  "XShear/Image"
+
+  typedef enum
+  {
+    LEFT,
+    RIGHT
+  } ShearDirection;
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    background;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetMagickPixelPacket(image,&background);
+  SetMagickPixelPacket(image,&image->background_color,(IndexPacket *) NULL,
+    &background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  /*
+    XShear image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,8) shared(progress, status)
+#endif
+  for (y=0; y < (long) height; y++)
+  {
+    long
+      step;
+
+    MagickPixelPacket
+      pixel,
+      source,
+      destination;
+
+    MagickRealType
+      area,
+      displacement;
+
+    register long
+      i;
+
+    register IndexPacket
+      *__restrict indexes,
+      *__restrict shear_indexes;
+
+    register PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    ShearDirection
+      direction;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewAuthenticPixels(image_view,0,y_offset+y,image->columns,1,
+      exception);
+    if (p == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    p+=x_offset;
+    indexes+=x_offset;
+    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=(long) floor((double) displacement);
+    area=(MagickRealType) (displacement-step);
+    step++;
+    pixel=background;
+    GetMagickPixelPacket(image,&source);
+    GetMagickPixelPacket(image,&destination);
+    switch (direction)
+    {
+      case LEFT:
+      {
+        /*
+          Transfer pixels left-to-right.
+        */
+        if (step > x_offset)
+          break;
+        q=p-step;
+        shear_indexes=indexes-step;
+        for (i=0; i < (long) width; i++)
+        {
+          if ((x_offset+i) < step)
+            {
+              SetMagickPixelPacket(image,++p,++indexes,&pixel);
+              q++;
+              shear_indexes++;
+              continue;
+            }
+          SetMagickPixelPacket(image,p,indexes,&source);
+          MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+            &source,(MagickRealType) p->opacity,area,&destination);
+          SetPixelPacket(image,&destination,q++,shear_indexes++);
+          SetMagickPixelPacket(image,p++,indexes++,&pixel);
+        }
+        MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+          &background,(MagickRealType) background.opacity,area,&destination);
+        SetPixelPacket(image,&destination,q++,shear_indexes++);
+        for (i=0; i < (step-1); i++)
+          SetPixelPacket(image,&background,q++,shear_indexes++);
+        break;
+      }
+      case RIGHT:
+      {
+        /*
+          Transfer pixels right-to-left.
+        */
+        p+=width;
+        indexes+=width;
+        q=p+step;
+        shear_indexes=indexes+step;
+        for (i=0; i < (long) width; i++)
+        {
+          p--;
+          indexes--;
+          q--;
+          shear_indexes--;
+          if ((unsigned long) (x_offset+width+step-i) >= image->columns)
+            continue;
+          SetMagickPixelPacket(image,p,indexes,&source);
+          MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+            &source,(MagickRealType) p->opacity,area,&destination);
+          SetPixelPacket(image,&destination,q,shear_indexes);
+          SetMagickPixelPacket(image,p,indexes,&pixel);
+        }
+        MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+          &background,(MagickRealType) background.opacity,area,&destination);
+        SetPixelPacket(image,&destination,--q,--shear_indexes);
+        for (i=0; i < (step-1); i++)
+          SetPixelPacket(image,&background,--q,--shear_indexes);
+        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 unsigned long width,const unsigned long height,
+%        const long x_offset,const long y_offset)
+%
+%  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.
+%
+*/
+static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
+  const unsigned long width,const unsigned long height,const long x_offset,
+  const long y_offset)
+{
+#define YShearImageTag  "YShear/Image"
+
+  typedef enum
+  {
+    UP,
+    DOWN
+  } ShearDirection;
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    x;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    background;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetMagickPixelPacket(image,&background);
+  SetMagickPixelPacket(image,&image->background_color,(IndexPacket *) NULL,
+    &background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  /*
+    Y Shear image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,8) shared(progress, status)
+#endif
+  for (x=0; x < (long) width; x++)
+  {
+    long
+      step;
+
+    MagickPixelPacket
+      pixel,
+      source,
+      destination;
+
+    MagickRealType
+      area,
+      displacement;
+
+    register IndexPacket
+      *__restrict indexes,
+      *__restrict shear_indexes;
+
+    register long
+      i;
+
+    register PixelPacket
+      *__restrict p,
+      *__restrict q;
+
+    ShearDirection
+      direction;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewAuthenticPixels(image_view,x_offset+x,0,1,image->rows,
+      exception);
+    if (p == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    p+=y_offset;
+    indexes+=y_offset;
+    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=(long) floor((double) displacement);
+    area=(MagickRealType) (displacement-step);
+    step++;
+    pixel=background;
+    GetMagickPixelPacket(image,&source);
+    GetMagickPixelPacket(image,&destination);
+    switch (direction)
+    {
+      case UP:
+      {
+        /*
+          Transfer pixels top-to-bottom.
+        */
+        if (step > y_offset)
+          break;
+        q=p-step;
+        shear_indexes=indexes-step;
+        for (i=0; i < (long) height; i++)
+        {
+          if ((y_offset+i) < step)
+            {
+              SetMagickPixelPacket(image,++p,++indexes,&pixel);
+              q++;
+              shear_indexes++;
+              continue;
+            }
+          SetMagickPixelPacket(image,p,indexes,&source);
+          MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+            &source,(MagickRealType) p->opacity,area,&destination);
+          SetPixelPacket(image,&destination,q++,shear_indexes++);
+          SetMagickPixelPacket(image,p++,indexes++,&pixel);
+        }
+        MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+          &background,(MagickRealType) background.opacity,area,&destination);
+        SetPixelPacket(image,&destination,q++,shear_indexes++);
+        for (i=0; i < (step-1); i++)
+          SetPixelPacket(image,&background,q++,shear_indexes++);
+        break;
+      }
+      case DOWN:
+      {
+        /*
+          Transfer pixels bottom-to-top.
+        */
+        p+=height;
+        indexes+=height;
+        q=p+step;
+        shear_indexes=indexes+step;
+        for (i=0; i < (long) height; i++)
+        {
+          p--;
+          indexes--;
+          q--;
+          shear_indexes--;
+          if ((unsigned long) (y_offset+height+step-i) >= image->rows)
+            continue;
+          SetMagickPixelPacket(image,p,indexes,&source);
+          MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+            &source,(MagickRealType) p->opacity,area,&destination);
+          SetPixelPacket(image,&destination,q,shear_indexes);
+          SetMagickPixelPacket(image,p,indexes,&pixel);
+        }
+        MagickPixelCompositeAreaBlend(&pixel,(MagickRealType) pixel.opacity,
+          &background,(MagickRealType) background.opacity,area,&destination);
+        SetPixelPacket(image,&destination,--q,--shear_indexes);
+        for (i=0; i < (step-1); i++)
+          SetPixelPacket(image,&background,--q,--shear_indexes);
+        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;
+
+  long
+    x_offset,
+    y_offset;
+
+  MagickRealType
+    angle;
+
+  PointInfo
+    shear;
+
+  RectangleInfo
+    border_info;
+
+  unsigned long
+    height,
+    rotations,
+    width,
+    y_width;
+
+  /*
+    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+(long) (fabs(shear.x)*height+0.5);
+  x_offset=(long) (width+((fabs(shear.y)*height)-width)/2.0+0.5);
+  y_offset=(long) (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=(unsigned long) x_offset;
+  border_info.height=(unsigned long) 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.
+  */
+  (void) XShearImage(rotate_image,shear.x,width,height,x_offset,
+    ((long) rotate_image->rows-height)/2);
+  (void) YShearImage(rotate_image,shear.y,y_width,height,
+    ((long) rotate_image->columns-y_width)/2,y_offset);
+  (void) XShearImage(rotate_image,shear.x,y_width,rotate_image->rows,
+    ((long) rotate_image->columns-y_width)/2,0);
+  CropToFitImage(&rotate_image,shear.x,shear.y,(MagickRealType) width,
+    (MagickRealType) height,MagickTrue,exception);
+  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;
+
+  long
+    x_offset,
+    y_offset;
+
+  PointInfo
+    shear;
+
+  RectangleInfo
+    border_info;
+
+  unsigned long
+    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+(long) (fabs(shear.x)*image->rows+0.5);
+  x_offset=(long) (image->columns+((fabs(shear.x)*image->rows)-image->columns)/
+    2.0+0.5);
+  y_offset=(long) (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=(unsigned long) x_offset;
+  border_info.height=(unsigned long) y_offset;
+  shear_image=BorderImage(integral_image,&border_info,exception);
+  if (shear_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  integral_image=DestroyImage(integral_image);
+  /*
+    Shear the image.
+  */
+  if (shear_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(shear_image,OpaqueAlphaChannel);
+  (void) XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset,
+    ((long) shear_image->rows-image->rows)/2);
+  (void) YShearImage(shear_image,shear.y,y_width,image->rows,
+    ((long) shear_image->columns-y_width)/2,y_offset);
+  CropToFitImage(&shear_image,shear.x,shear.y,(MagickRealType) image->columns,
+    (MagickRealType) image->rows,MagickFalse,exception);
+  shear_image->compose=image->compose;
+  shear_image->page.width=0;
+  shear_image->page.height=0;
+  return(shear_image);
+}
diff --git a/magick/shear.h b/magick/shear.h
new file mode 100644
index 0000000..2c33572
--- /dev/null
+++ b/magick/shear.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2009 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/magick/signature-private.h b/magick/signature-private.h
new file mode 100644
index 0000000..a3d8c5b
--- /dev/null
+++ b/magick/signature-private.h
@@ -0,0 +1,56 @@
+/*
+  Copyright 1999-2009 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 <magick/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/magick/signature.c b/magick/signature.c
new file mode 100644
index 0000000..2d48678
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/property.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/signature.h"
+#include "magick/signature-private.h"
+#include "magick/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;
+
+  long
+    timestamp;
+
+  unsigned long
+    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=(long) 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 long
+    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                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IntializeSignature() intializes 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)
+{
+  char
+    *hex_signature;
+
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  register const PixelPacket
+    *p;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    length;
+
+  StringInfo
+    *signature;
+
+  unsigned char
+    *pixels;
+
+  CacheView
+    *image_view;
+
+  /*
+    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 < (long) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) 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))
+
+  long
+    j;
+
+  register long
+    i;
+
+  register unsigned char
+    *p;
+
+  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/magick/signature.h b/magick/signature.h
new file mode 100644
index 0000000..668d509
--- /dev/null
+++ b/magick/signature.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2009 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/magick/splay-tree.c b/magick/splay-tree.c
new file mode 100644
index 0000000..523aa95
--- /dev/null
+++ b/magick/splay-tree.c
@@ -0,0 +1,1619 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/splay-tree.h"
+#include "magick/semaphore.h"
+#include "magick/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;
+
+  unsigned long
+    nodes;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    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;
+
+  (void) 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_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;
+          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->value=(void *) value;
+          (void) UnlockSemaphoreInfo(splay_tree->semaphore);
+          return(MagickTrue);
+        }
+    }
+  node=(NodeInfo *) AcquireMagickMemory(sizeof(*node));
+  if (node == (NodeInfo *) NULL)
+    {
+      (void) 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++;
+  (void) 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 unsigned long low,
+  const unsigned long high)
+{
+  register NodeInfo
+    *node;
+
+  unsigned long
+    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.
+%
+*/
+MagickExport SplayTreeInfo *CloneSplayTree(SplayTreeInfo *splay_tree,
+  void *(*clone_key)(void *),void *(*clone_value)(void *))
+{
+  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);
+  (void) LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      register NodeInfo
+        *active,
+        *next,
+        *node;
+
+      void
+        *key,
+        *value;
+
+      key=splay_tree->root->key;
+      if ((clone_key != (void *(*)(void *)) NULL) && (key != (void *) NULL))
+        key=clone_key(key);
+      value=splay_tree->root->value;
+      if ((clone_value != (void *(*)(void *)) NULL) && (value != (void *) NULL))
+        value=clone_value(value);
+      (void) AddValueToSplayTree(clone_tree,key,value);
+      for (node=splay_tree->root; node != (NodeInfo *) NULL; )
+      {
+        active=node;
+        for (node=(NodeInfo *) NULL; active != (NodeInfo *) NULL; )
+        {
+          next=(NodeInfo *) NULL;
+          if (active->left != (NodeInfo *) NULL)
+            {
+              next=node;
+              key=active->left->key;
+              if ((clone_key != (void *(*)(void *)) NULL) &&
+                  (key != (void *) NULL))
+                key=clone_key(key);
+              value=active->left->value;
+              if ((clone_value != (void *(*)(void *)) NULL) &&
+                  (value != (void *) NULL))
+                value=clone_value(value);
+              (void) AddValueToSplayTree(clone_tree,key,value);
+              node=active->left;
+            }
+          if (active->right != (NodeInfo *) NULL)
+            {
+              next=node;
+              key=active->right->key;
+              if ((clone_key != (void *(*)(void *)) NULL) &&
+                  (key != (void *) NULL))
+                key=clone_key(key);
+              value=active->right->value;
+              if ((clone_value != (void *(*)(void *)) NULL) &&
+                  (value != (void *) NULL))
+                value=clone_value(value);
+              (void) AddValueToSplayTree(clone_tree,key,value);
+              node=active->right;
+            }
+          active=next;
+        }
+      }
+    }
+  (void) 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.
+%
+*/
+
+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 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(),"...");
+  (void) LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root == (NodeInfo *) NULL)
+    {
+      (void) 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)
+          {
+            (void) UnlockSemaphoreInfo(splay_tree->semaphore);
+            return(MagickFalse);
+          }
+        left=splay_tree->root->left;
+        right=splay_tree->root->right;
+        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);
+        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;
+            (void) 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;
+          }
+        (void) UnlockSemaphoreInfo(splay_tree->semaphore);
+        return(MagickTrue);
+      }
+  }
+  (void) 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);
+  (void) 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)
+    {
+      (void) 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;
+      (void) 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;
+    }
+  (void) 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;
+
+  (void) LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      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;
+      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);
+      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_key != (void *(*)(void *)) NULL) &&
+                  (active->left->key != (void *) NULL))
+                active->left->key=splay_tree->relinquish_key(active->left->key);
+              active->left->key=(void *) pend;
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->left->value != (void *) NULL))
+                active->left->value=splay_tree->relinquish_value(
+                  active->left->value);
+              pend=active->left;
+            }
+          if (active->right != (NodeInfo *) NULL)
+            {
+              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;
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->right->value != (void *) NULL))
+                active->right->value=splay_tree->relinquish_value(
+                  active->right->value);
+              pend=active->right;
+            }
+          node=active;
+          active=(NodeInfo *) node->key;
+          node=(NodeInfo *) RelinquishMagickMemory(node);
+        }
+      }
+    }
+  splay_tree->signature=(~MagickSignature);
+  (void) 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:
+%
+%      void *GetNextKeyInSplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o key: the key.
+%
+*/
+MagickExport 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);
+  (void) 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;
+  (void) 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:
+%
+%      void *GetNextValueInSplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o key: the key.
+%
+*/
+MagickExport 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);
+  (void) 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;
+  (void) 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.
+%
+%  The format of the GetValueFromSplayTree method is:
+%
+%      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 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);
+  (void) 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)
+    {
+      (void) UnlockSemaphoreInfo(splay_tree->semaphore);
+      return((void *) NULL);
+    }
+  value=splay_tree->root->value;
+  (void) 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:
+%
+%      unsigned long GetNumberOfNodesInSplayTree(
+%        const SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+*/
+MagickExport unsigned long 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 long
+    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);
+  (void) 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)
+          {
+            (void) 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;
+            (void) 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;
+          }
+        (void) UnlockSemaphoreInfo(splay_tree->semaphore);
+        return(key);
+      }
+  }
+  (void) 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);
+  (void) 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)
+    {
+      (void) 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;
+      (void) 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;
+    }
+  (void) 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(),"...");
+  (void) LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      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;
+      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);
+      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_key != (void *(*)(void *)) NULL) &&
+                  (active->left->key != (void *) NULL))
+                active->left->key=splay_tree->relinquish_key(active->left->key);
+              active->left->key=(void *) pend;
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->left->value != (void *) NULL))
+                active->left->value=splay_tree->relinquish_value(
+                  active->left->value);
+              pend=active->left;
+            }
+          if (active->right != (NodeInfo *) NULL)
+            {
+              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;
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->right->value != (void *) NULL))
+                active->right->value=splay_tree->relinquish_value(
+                  active->right->value);
+              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;
+  (void) 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(),"...");
+  (void) LockSemaphoreInfo(splay_tree->semaphore);
+  splay_tree->next=GetFirstSplayTreeNode(splay_tree);
+  (void) 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 unsigned long 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/magick/splay-tree.h b/magick/splay-tree.h
new file mode 100644
index 0000000..c407875
--- /dev/null
+++ b/magick/splay-tree.h
@@ -0,0 +1,59 @@
+/*
+  Copyright 1999-2009 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 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 unsigned long
+  GetNumberOfNodesInSplayTree(const SplayTreeInfo *);
+
+extern MagickExport void
+  *GetNextKeyInSplayTree(SplayTreeInfo *),
+  *GetNextValueInSplayTree(SplayTreeInfo *),
+  *GetValueFromSplayTree(SplayTreeInfo *,const void *),
+  *RemoveNodeByValueFromSplayTree(SplayTreeInfo *,const void *),
+  *RemoveNodeFromSplayTree(SplayTreeInfo *,const void *),
+  ResetSplayTree(SplayTreeInfo *),
+  ResetSplayTreeIterator(SplayTreeInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/stamp-h.in b/magick/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/magick/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/magick/stamp-h1 b/magick/stamp-h1
new file mode 100644
index 0000000..7bb7372
--- /dev/null
+++ b/magick/stamp-h1
@@ -0,0 +1 @@
+timestamp for magick/magick-config.h
diff --git a/magick/static.c b/magick/static.c
new file mode 100644
index 0000000..63130fe
--- /dev/null
+++ b/magick/static.c
@@ -0,0 +1,469 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/module.h"
+#include "magick/policy.h"
+#include "magick/static.h"
+#include "magick/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)
+    {
+      (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 unsigned long
+      analyzeImage(Image **,const int,char **,ExceptionInfo *);
+
+    ImageFilterHandler
+      *image_filter;
+
+    image_filter=(ImageFilterHandler *) NULL;
+    if (LocaleCompare("analyze",tag) == 0)
+      image_filter=analyzeImage;
+    if (image_filter != (ImageFilterHandler *) NULL)
+      {
+        unsigned long
+          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,signature,
+              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) RegisterARTImage();
+  (void) RegisterAVIImage();
+  (void) RegisterAVSImage();
+  (void) RegisterBMPImage();
+  (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) RegisterDIBImage();
+#if defined(MAGICKCORE_DJVU_DELEGATE)
+  (void) RegisterDJVUImage();
+#endif
+  (void) RegisterDNGImage();
+  (void) RegisterDPSImage();
+  (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) 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) 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) 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_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)
+  UnregisterARTImage();
+  UnregisterAVIImage();
+  UnregisterAVSImage();
+  UnregisterBMPImage();
+  UnregisterBRAILLEImage();
+  UnregisterCAPTIONImage();
+  UnregisterCINImage();
+  UnregisterCIPImage();
+  UnregisterCLIPImage();
+#if defined(MAGICKCORE_WINGDI32_DELEGATE)
+  UnregisterCLIPBOARDImage();
+#endif
+  UnregisterCMYKImage();
+  UnregisterCUTImage();
+  UnregisterDCMImage();
+  UnregisterDDSImage();
+  UnregisterDIBImage();
+#if defined(MAGICKCORE_DJVU_DELEGATE)
+  UnregisterDJVUImage();
+#endif
+  UnregisterDNGImage();
+  UnregisterDPSImage();
+  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();
+  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();
+  UnregisterMAGICKImage();
+  UnregisterMAPImage();
+  UnregisterMATImage();
+  UnregisterMATTEImage();
+  UnregisterMETAImage();
+  UnregisterMIFFImage();
+  UnregisterMONOImage();
+  UnregisterMPCImage();
+  UnregisterMPEGImage();
+  UnregisterMPRImage();
+  UnregisterMSLImage();
+  UnregisterMTVImage();
+  UnregisterMVGImage();
+  UnregisterNULLImage();
+  UnregisterOTBImage();
+  UnregisterPALMImage();
+  UnregisterPATTERNImage();
+  UnregisterPCDImage();
+  UnregisterPCLImage();
+  UnregisterPCXImage();
+  UnregisterPDBImage();
+  UnregisterPDFImage();
+  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_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/magick/static.h b/magick/static.h
new file mode 100644
index 0000000..d4aa1b1
--- /dev/null
+++ b/magick/static.h
@@ -0,0 +1,324 @@
+/*
+  Copyright 1999-2009 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 unsigned long
+  RegisterARTImage(void),
+  RegisterAVIImage(void),
+  RegisterAVSImage(void),
+  RegisterBIEImage(void),
+  RegisterBMPImage(void),
+  RegisterBRAILLEImage(void),
+  RegisterCAPTIONImage(void),
+  RegisterCINImage(void),
+  RegisterCIPImage(void),
+  RegisterCLIPImage(void),
+  RegisterCLIPBOARDImage(void),
+  RegisterCMYKImage(void),
+  RegisterCUTImage(void),
+  RegisterDCMImage(void),
+  RegisterDCXImage(void),
+  RegisterDDSImage(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),
+  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),
+  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),
+  RegisterPICImage(void),
+  RegisterPICTImage(void),
+  RegisterPIXImage(void),
+  RegisterPLASMAImage(void),
+  RegisterPGMImage(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),
+  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
+  UnregisterARTImage(void),
+  UnregisterAVIImage(void),
+  UnregisterAVSImage(void),
+  UnregisterBIEImage(void),
+  UnregisterBMPImage(void),
+  UnregisterBRAILLEImage(void),
+  UnregisterCAPTIONImage(void),
+  UnregisterCINImage(void),
+  UnregisterCIPImage(void),
+  UnregisterCLIPImage(void),
+  UnregisterCLIPBOARDImage(void),
+  UnregisterCMYKImage(void),
+  UnregisterCUTImage(void),
+  UnregisterDCMImage(void),
+  UnregisterDCXImage(void),
+  UnregisterDDSImage(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),
+  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),
+  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),
+  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),
+  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/magick/statistic.c b/magick/statistic.c
new file mode 100644
index 0000000..ac227ac
--- /dev/null
+++ b/magick/statistic.c
@@ -0,0 +1,1404 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        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 Methods                           %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/animate.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/cache-view.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/composite-private.h"
+#include "magick/compress.h"
+#include "magick/constitute.h"
+#include "magick/deprecate.h"
+#include "magick/display.h"
+#include "magick/draw.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/image-private.h"
+#include "magick/magic.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/module.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/paint.h"
+#include "magick/pixel-private.h"
+#include "magick/profile.h"
+#include "magick/quantize.h"
+#include "magick/random_.h"
+#include "magick/segment.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/thread-private.h"
+#include "magick/timer.h"
+#include "magick/utility.h"
+#include "magick/version.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)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    target[3],
+    zero;
+
+  RectangleInfo
+    bounds;
+
+  register const PixelPacket
+    *p;
+
+  CacheView
+    *image_view;
+
+  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=(long) image->columns;
+  bounds.y=(long) image->rows;
+  GetMagickPixelPacket(image,&target[0]);
+  image_view=AcquireCacheView(image);
+  p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
+  if (p == (const PixelPacket *) NULL)
+    {
+      image_view=DestroyCacheView(image_view);
+      return(bounds);
+    }
+  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
+    &target[0]);
+  GetMagickPixelPacket(image,&target[1]);
+  p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
+    exception);
+  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
+    &target[1]);
+  GetMagickPixelPacket(image,&target[2]);
+  p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
+  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
+    &target[2]);
+  status=MagickTrue;
+  GetMagickPixelPacket(image,&zero);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    MagickPixelPacket
+      pixel;
+
+    RectangleInfo
+      bounding_box;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    if (status == MagickFalse)
+      continue;
+#if defined(HAVE_OPENMP)
+#  pragma omp critical (MagickCore_GetImageBoundingBox)
+#endif
+    bounding_box=bounds;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    pixel=zero;
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,p,indexes+x,&pixel);
+      if ((x < bounding_box.x) &&
+          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
+        bounding_box.x=x;
+      if ((x > (long) bounding_box.width) &&
+          (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
+        bounding_box.width=(unsigned long) x;
+      if ((y < bounding_box.y) &&
+          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
+        bounding_box.y=y;
+      if ((y > (long) bounding_box.height) &&
+          (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
+        bounding_box.height=(unsigned long) y;
+      p++;
+    }
+#if defined(HAVE_OPENMP)
+#  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:
+%
+%      unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
+%      unsigned long 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 unsigned long GetImageDepth(const Image *image,
+  ExceptionInfo *exception)
+{
+  return(GetImageChannelDepth(image,AllChannels,exception));
+}
+
+MagickExport unsigned long GetImageChannelDepth(const Image *image,
+  const ChannelType channel,ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  register long
+    id;
+
+  unsigned long
+    *current_depth,
+    depth,
+    number_threads;
+
+  CacheView
+    *image_view;
+
+  /*
+    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=(unsigned long *) AcquireQuantumMemory(number_threads,
+    sizeof(*current_depth));
+  if (current_depth == (unsigned long *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  status=MagickTrue;
+  for (id=0; id < (long) number_threads; id++)
+    current_depth[id]=1;
+  if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      register long
+        i;
+
+      p=image->colormap;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (i=0; i < (long) image->colors; i++)
+      {
+        if (status == MagickFalse)
+          continue;
+        id=GetOpenMPThreadId();
+        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 < (long) number_threads; id++)
+        if (depth < current_depth[id])
+          depth=current_depth[id];
+      current_depth=(unsigned long *) 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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      id,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    id=GetOpenMPThreadId();
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      continue;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    for (x=0; x < (long) 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|=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 (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
+          status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
+            range),range);
+        if (((channel & IndexChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
+            range),range);
+        if (status == 0)
+          break;
+        current_depth[id]++;
+      }
+      p++;
+    }
+    if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  depth=current_depth[0];
+  for (id=1; id < (long) number_threads; id++)
+    if (depth < current_depth[id])
+      depth=current_depth[id];
+  current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
+  return(depth);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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,unsigned long *minima,unsigned long *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,
+  unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
+{
+  return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
+}
+
+MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
+  const ChannelType channel,unsigned long *minima,unsigned long *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=(unsigned long) (min+0.5);
+  *maxima=(unsigned long) (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,AllChannels,mean,standard_deviation,
+    exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
+  const ChannelType channel,double *mean,double *standard_deviation,
+  ExceptionInfo *exception)
+{
+  double
+    area;
+
+  long
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *mean=0.0;
+  *standard_deviation=0.0;
+  area=0.0;
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          *mean+=p->red;
+          *standard_deviation+=(double) p->red*p->red;
+          area++;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          *mean+=p->green;
+          *standard_deviation+=(double) p->green*p->green;
+          area++;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          *mean+=p->blue;
+          *standard_deviation+=(double) p->blue*p->blue;
+          area++;
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          *mean+=p->opacity;
+          *standard_deviation+=(double) p->opacity*p->opacity;
+          area++;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          *mean+=indexes[x];
+          *standard_deviation+=(double) indexes[x]*indexes[x];
+          area++;
+        }
+      p++;
+    }
+  }
+  if (y < (long) image->rows)
+    return(MagickFalse);
+  if (area != 0)
+    {
+      *mean/=area;
+      *standard_deviation/=area;
+    }
+  *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
+  return(y == (long) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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,AllChannels,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;
+
+  long
+    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 < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          mean+=p->red;
+          sum_squares+=(double) p->red*p->red;
+          sum_cubes+=(double) p->red*p->red*p->red;
+          sum_fourth_power+=(double) p->red*p->red*p->red*p->red;
+          area++;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          mean+=p->green;
+          sum_squares+=(double) p->green*p->green;
+          sum_cubes+=(double) p->green*p->green*p->green;
+          sum_fourth_power+=(double) p->green*p->green*p->green*p->green;
+          area++;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          mean+=p->blue;
+          sum_squares+=(double) p->blue*p->blue;
+          sum_cubes+=(double) p->blue*p->blue*p->blue;
+          sum_fourth_power+=(double) p->blue*p->blue*p->blue*p->blue;
+          area++;
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          mean+=p->opacity;
+          sum_squares+=(double) p->opacity*p->opacity;
+          sum_cubes+=(double) p->opacity*p->opacity*p->opacity;
+          sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
+            p->opacity;
+          area++;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          mean+=indexes[x];
+          sum_squares+=(double) indexes[x]*indexes[x];
+          sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
+          sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
+            indexes[x];
+          area++;
+        }
+      p++;
+    }
+  }
+  if (y < (long) 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 == (long) 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,AllChannels,minima,maxima,exception));
+}
+
+MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
+  const ChannelType channel,double *minima,double *maxima,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickPixelPacket
+    pixel;
+
+  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;
+  GetMagickPixelPacket(image,&pixel);
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      SetMagickPixelPacket(image,p,indexes+x,&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 & OpacityChannel) != 0)
+        {
+          if (pixel.opacity < *minima)
+            *minima=(double) pixel.opacity;
+          if (pixel.opacity > *maxima)
+            *maxima=(double) pixel.opacity;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if ((double) indexes[x] < *minima)
+            *minima=(double) indexes[x];
+          if ((double) indexes[x] > *maxima)
+            *maxima=(double) indexes[x];
+        }
+      p++;
+    }
+  }
+  return(y == (long) 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,excepton);
+%      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.
+%
+*/
+
+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 ChannelStatistics *GetImageChannelStatistics(const Image *image,
+  ExceptionInfo *exception)
+{
+  ChannelStatistics
+    *channel_statistics;
+
+  double
+    area,
+    sum_squares,
+    sum_cubes;
+
+  long
+    y;
+
+  MagickStatusType
+    status;
+
+  QuantumAny
+    range;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  unsigned long
+    channels,
+    depth;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  length=AllChannels+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 <= AllChannels; i++)
+  {
+    channel_statistics[i].depth=1;
+    channel_statistics[i].maxima=(-1.0E-37);
+    channel_statistics[i].minima=1.0E+37;
+    channel_statistics[i].mean=0.0;
+    channel_statistics[i].standard_deviation=0.0;
+    channel_statistics[i].kurtosis=0.0;
+    channel_statistics[i].skewness=0.0;
+  }
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register long
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    indexes=GetVirtualIndexQueue(image);
+    for (x=0; x < (long) image->columns; )
+    {
+      if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+        {
+          depth=channel_statistics[RedChannel].depth;
+          range=GetQuantumRange(depth);
+          status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,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=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
+            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=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
+            range),range) ? MagickTrue : MagickFalse;
+          if (status != MagickFalse)
+            {
+              channel_statistics[BlueChannel].depth++;
+              continue;
+            }
+        }
+      if (image->matte != MagickFalse)
+        {
+          if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+            {
+              depth=channel_statistics[OpacityChannel].depth;
+              range=GetQuantumRange(depth);
+              status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
+                p->opacity,range),range) ? MagickTrue : MagickFalse;
+              if (status != MagickFalse)
+                {
+                  channel_statistics[OpacityChannel].depth++;
+                  continue;
+                }
+            }
+          }
+      if (image->colorspace == CMYKColorspace)
+        {
+          if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+            {
+              depth=channel_statistics[BlackChannel].depth;
+              range=GetQuantumRange(depth);
+              status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
+                indexes[x],range),range) ? MagickTrue : MagickFalse;
+              if (status != MagickFalse)
+                {
+                  channel_statistics[BlackChannel].depth++;
+                  continue;
+                }
+            }
+        }
+      if ((double) p->red < channel_statistics[RedChannel].minima)
+        channel_statistics[RedChannel].minima=(double) p->red;
+      if ((double) p->red > channel_statistics[RedChannel].maxima)
+        channel_statistics[RedChannel].maxima=(double) p->red;
+      channel_statistics[RedChannel].mean+=p->red;
+      channel_statistics[RedChannel].standard_deviation+=(double) p->red*p->red;
+      channel_statistics[RedChannel].kurtosis+=(double) p->red*p->red*
+        p->red*p->red;
+      channel_statistics[RedChannel].skewness+=(double) p->red*p->red*p->red;
+      if ((double) p->green < channel_statistics[GreenChannel].minima)
+        channel_statistics[GreenChannel].minima=(double) p->green;
+      if ((double) p->green > channel_statistics[GreenChannel].maxima)
+        channel_statistics[GreenChannel].maxima=(double) p->green;
+      channel_statistics[GreenChannel].mean+=p->green;
+      channel_statistics[GreenChannel].standard_deviation+=(double) p->green*
+        p->green;
+      channel_statistics[GreenChannel].kurtosis+=(double) p->green*p->green*
+        p->green*p->green;
+      channel_statistics[GreenChannel].skewness+=(double) p->green*p->green*
+        p->green;
+      if ((double) p->blue < channel_statistics[BlueChannel].minima)
+        channel_statistics[BlueChannel].minima=(double) p->blue;
+      if ((double) p->blue > channel_statistics[BlueChannel].maxima)
+        channel_statistics[BlueChannel].maxima=(double) p->blue;
+      channel_statistics[BlueChannel].mean+=p->blue;
+      channel_statistics[BlueChannel].standard_deviation+=(double) p->blue*
+        p->blue;
+      channel_statistics[BlueChannel].kurtosis+=(double) p->blue*p->blue*
+        p->blue*p->blue;
+      channel_statistics[BlueChannel].skewness+=(double) p->blue*p->blue*
+        p->blue;
+      if (image->matte != MagickFalse)
+        {
+          if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
+            channel_statistics[OpacityChannel].minima=(double) p->opacity;
+          if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
+            channel_statistics[OpacityChannel].maxima=(double) p->opacity;
+          channel_statistics[OpacityChannel].mean+=p->opacity;
+          channel_statistics[OpacityChannel].standard_deviation+=(double)
+            p->opacity*p->opacity;
+          channel_statistics[OpacityChannel].kurtosis+=(double) p->opacity*
+            p->opacity*p->opacity*p->opacity;
+          channel_statistics[OpacityChannel].skewness+=(double) p->opacity*
+            p->opacity*p->opacity;
+        }
+      if (image->colorspace == CMYKColorspace)
+        {
+          if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
+            channel_statistics[BlackChannel].minima=(double) indexes[x];
+          if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
+            channel_statistics[BlackChannel].maxima=(double) indexes[x];
+          channel_statistics[BlackChannel].mean+=indexes[x];
+          channel_statistics[BlackChannel].standard_deviation+=(double)
+            indexes[x]*indexes[x];
+          channel_statistics[BlackChannel].kurtosis+=(double) indexes[x]*
+            indexes[x]*indexes[x]*indexes[x];
+          channel_statistics[BlackChannel].skewness+=(double) indexes[x]*
+            indexes[x]*indexes[x];
+        }
+      x++;
+      p++;
+    }
+  }
+  area=(double) image->columns*image->rows;
+  for (i=0; i < AllChannels; i++)
+  {
+    channel_statistics[i].mean/=area;
+    channel_statistics[i].standard_deviation/=area;
+    channel_statistics[i].kurtosis/=area;
+    channel_statistics[i].skewness/=area;
+  }
+  for (i=0; i < AllChannels; i++)
+  {
+    channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double)
+      channel_statistics[AllChannels].depth,(double)
+      channel_statistics[i].depth);
+    channel_statistics[AllChannels].minima=MagickMin(
+      channel_statistics[AllChannels].minima,channel_statistics[i].minima);
+    channel_statistics[AllChannels].maxima=MagickMax(
+      channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
+    channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
+    channel_statistics[AllChannels].standard_deviation+=
+      channel_statistics[i].standard_deviation;
+    channel_statistics[AllChannels].kurtosis+=channel_statistics[i].kurtosis;
+    channel_statistics[AllChannels].skewness+=channel_statistics[i].skewness;
+  }
+  channels=4;
+  if (image->colorspace == CMYKColorspace)
+    channels++;
+  channel_statistics[AllChannels].mean/=channels;
+  channel_statistics[AllChannels].standard_deviation/=channels;
+  channel_statistics[AllChannels].kurtosis/=channels;
+  channel_statistics[AllChannels].skewness/=channels;
+  for (i=0; i <= AllChannels; i++)
+  {
+    sum_squares=0.0;
+    sum_squares=channel_statistics[i].standard_deviation;
+    sum_cubes=0.0;
+    sum_cubes=channel_statistics[i].skewness;
+    channel_statistics[i].standard_deviation=sqrt(
+      channel_statistics[i].standard_deviation-
+       (channel_statistics[i].mean*channel_statistics[i].mean));
+    if (channel_statistics[i].standard_deviation == 0.0)
+      {
+        channel_statistics[i].kurtosis=0.0;
+        channel_statistics[i].skewness=0.0;
+      }
+    else
+      {
+        channel_statistics[i].skewness=(channel_statistics[i].skewness-
+          3.0*channel_statistics[i].mean*sum_squares+
+          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].kurtosis-
+          4.0*channel_statistics[i].mean*sum_cubes+
+          6.0*channel_statistics[i].mean*channel_statistics[i].mean*sum_squares-
+          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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      unsigned long 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.
+%
+*/
+MagickExport unsigned long GetImageQuantumDepth(const Image *image,
+  const MagickBooleanType constrain)
+{
+  unsigned long
+    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=(unsigned long) MagickMin((double) depth,(double)
+      MAGICKCORE_QUANTUM_DEPTH);
+  return(depth);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 unsigned long depth)
+%      MagickBooleanType SetImageChannelDepth(Image *image,
+%        const ChannelType channel,const unsigned long 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 unsigned long depth)
+{
+  return(SetImageChannelDepth(image,AllChannels,depth));
+}
+
+MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
+  const ChannelType channel,const unsigned long depth)
+{
+  ExceptionInfo
+    *exception;
+
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  QuantumAny
+    range;
+
+  CacheView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (GetImageDepth(image,&image->exception) <= (unsigned long)
+      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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,range),range);
+      if ((channel & GreenChannel) != 0)
+        q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,range),range);
+      if ((channel & BlueChannel) != 0)
+        q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,range),range);
+      if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
+        q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,range),range);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],range),range);
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      {
+        status=MagickFalse;
+        continue;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (image->storage_class == PseudoClass)
+    {
+      QuantumAny
+        range;
+
+      register long
+        i;
+
+      register PixelPacket
+        *__restrict p;
+
+      p=image->colormap;
+      range=GetQuantumRange(depth);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (i=0; i < (long) 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 & OpacityChannel) != 0)
+          p->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,range),
+            range);
+        p++;
+      }
+    }
+  image->depth=depth;
+  return(status);
+}
diff --git a/magick/statistic.h b/magick/statistic.h
new file mode 100644
index 0000000..8369e6f
--- /dev/null
+++ b/magick/statistic.h
@@ -0,0 +1,71 @@
+/*
+  Copyright 1999-2009 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_STATISTIC_H
+#define _MAGICKCORE_STATISTIC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _ChannelStatistics
+{
+  unsigned long
+    depth;
+
+  double
+    minima,
+    maxima,
+    mean,
+    standard_deviation,
+    kurtosis,
+    skewness;
+} ChannelStatistics;
+
+extern MagickExport ChannelStatistics
+  *GetImageChannelStatistics(const Image *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  GetImageChannelExtrema(const Image *,const ChannelType,unsigned long *,
+    unsigned long *,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 *,unsigned long *,unsigned long *,
+    ExceptionInfo *),
+  GetImageRange(const Image *,double *,double *,ExceptionInfo *),
+  GetImageMean(const Image *,double *,double *,ExceptionInfo *),
+  GetImageKurtosis(const Image *,double *,double *,ExceptionInfo *),
+  SetImageChannelDepth(Image *,const ChannelType,const unsigned long),
+  SetImageDepth(Image *,const unsigned long);
+
+extern MagickExport RectangleInfo
+  GetImageBoundingBox(const Image *,ExceptionInfo *exception);
+
+extern MagickExport unsigned long
+  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/magick/stream-private.h b/magick/stream-private.h
new file mode 100644
index 0000000..7e6b164
--- /dev/null
+++ b/magick/stream-private.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2009 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/magick/stream.c b/magick/stream.c
new file mode 100644
index 0000000..6dd1ff1
--- /dev/null
+++ b/magick/stream.c
@@ -0,0 +1,2693 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/cache-private.h"
+#include "magick/color-private.h"
+#include "magick/composite-private.h"
+#include "magick/constitute.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/memory_.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/semaphore.h"
+#include "magick/stream.h"
+#include "magick/stream-private.h"
+#include "magick/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;
+
+  long
+    y;
+
+  ExceptionInfo
+    *exception;
+
+  const void
+    *client_data;
+
+  unsigned long
+    signature;
+};
+
+/*
+  Declare pixel cache interfaces.
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const PixelPacket
+  *GetVirtualPixelStream(const Image *,const VirtualPixelMethod,const long,
+    const long,const unsigned long,const unsigned long,ExceptionInfo *);
+
+static MagickBooleanType
+  StreamImagePixels(const StreamInfo *,const Image *,ExceptionInfo *),
+  SyncAuthenticPixelsStream(Image *,ExceptionInfo *);
+
+static PixelPacket
+  *QueueAuthenticPixelsStream(Image *,const long,const long,const unsigned long,
+    const unsigned long,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=(PixelPacket *) NULL;
+  cache_info->indexes=(IndexPacket *) 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;
+  (void) LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count--;
+  if (cache_info->reference_count == 0)
+    destroy=MagickTrue;
+  (void) 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 I n d e x e s F r o m S t r e a m                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticIndexesFromStream() returns the indexes associated with the
+%  last call to QueueAuthenticPixelsStream() or GetAuthenticPixelsStream().
+%
+%  The format of the GetAuthenticIndexesFromStream() method is:
+%
+%      IndexPacket *GetAuthenticIndexesFromStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static IndexPacket *GetAuthenticIndexesFromStream(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->indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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:
+%
+%      PixelPacket *GetAuthenticPixelsStream(Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *GetAuthenticPixelsStream(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long rows,
+  ExceptionInfo *exception)
+{
+  PixelPacket
+    *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:
+%
+%      PixelPacket *GetAuthenticPixelsFromStream(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static PixelPacket *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 long x,const long 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 long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  register PixelPacket
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *pixel=image->background_color;
+  pixels=GetAuthenticPixelsStream(image,x,y,1,1,exception);
+  if (pixels != (PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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 long x,
+%        const long 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 long x,const long y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const PixelPacket
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *pixel=image->background_color;
+  pixels=GetVirtualPixelStream(image,virtual_pixel_method,x,y,1,1,exception);
+  if (pixels != (const PixelPacket *) NULL)
+    return(MagickFalse);
+  *pixel=(*pixels);
+  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 IndexPacket *GetVirtualPixelsStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o pixels: return the pixels associated with the last call to
+%      QueueAuthenticPixelsStream() or GetVirtualPixelStream().
+%
+%    o image: the image.
+%
+*/
+static const PixelPacket *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                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualIndexesFromStream() returns the indexes associated with the last
+%  call to QueueAuthenticPixelsStream() or GetVirtualPixelStream().
+%
+%  The format of the GetVirtualIndexesFromStream() method is:
+%
+%      const IndexPacket *GetVirtualIndexesFromStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const IndexPacket *GetVirtualIndexesFromStream(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->indexes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 PixelPacket *GetVirtualPixelStream(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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=(PixelPacket *) AcquireMagickMemory((size_t)
+    cache_info->length);
+  if (cache_info->pixels == (PixelPacket *) NULL)
+    {
+      cache_info->mapped=MagickTrue;
+      cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
+        cache_info->length);
+    }
+  if (cache_info->pixels == (PixelPacket *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+static const PixelPacket *GetVirtualPixelStream(const Image *image,
+  const VirtualPixelMethod magick_unused(virtual_pixel_method),const long x,
+  const long y,const unsigned long columns,const unsigned long 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+(long) columns) > (long) image->columns) ||
+      ((y+(long) rows) > (long) image->rows) || (columns == 0) || (rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "ImageDoesNotContainTheStreamGeometry","`%s'",image->filename);
+      return((PixelPacket *) 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*sizeof(PixelPacket);
+  if ((image->storage_class == PseudoClass) ||
+      (image->colorspace == CMYKColorspace))
+    length+=number_pixels*sizeof(IndexPacket);
+  if (cache_info->pixels == (PixelPacket *) NULL)
+    {
+      cache_info->length=length;
+      status=AcquireStreamPixels(cache_info,exception);
+      if (status == MagickFalse)
+        return((PixelPacket *) NULL);
+    }
+  else
+    if (cache_info->length != length)
+      {
+        RelinquishStreamPixels(cache_info);
+        cache_info->length=length;
+        status=AcquireStreamPixels(cache_info,exception);
+        if (status == MagickFalse)
+          return((PixelPacket *) NULL);
+      }
+  cache_info->indexes=(IndexPacket *) NULL;
+  if ((image->storage_class == PseudoClass) ||
+      (image->colorspace == CMYKColorspace))
+    cache_info->indexes=(IndexPacket *) (cache_info->pixels+number_pixels);
+  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:
+%
+%      PixelPacket *QueueAuthenticPixelsStream(Image *image,const long x,
+%        const long y,const unsigned long columns,const unsigned long 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 PixelPacket *QueueAuthenticPixelsStream(Image *image,const long x,
+  const long y,const unsigned long columns,const unsigned long 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+(long) columns) > (long) image->columns) ||
+      ((y+(long) rows) > (long) image->rows) || (columns == 0) || (rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "ImageDoesNotContainTheStreamGeometry","`%s'",image->filename);
+      return((PixelPacket *) NULL);
+    }
+  stream_handler=GetBlobStreamHandler(image);
+  if (stream_handler == (StreamHandler) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "NoStreamHandlerIsDefined","`%s'",image->filename);
+      return((PixelPacket *) 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*sizeof(PixelPacket);
+  if ((image->storage_class == PseudoClass) ||
+      (image->colorspace == CMYKColorspace))
+    length+=number_pixels*sizeof(IndexPacket);
+  if (cache_info->pixels == (PixelPacket *) NULL)
+    {
+      cache_info->pixels=(PixelPacket *) AcquireMagickMemory(length);
+      cache_info->length=(MagickSizeType) length;
+    }
+  else
+    if (cache_info->length < (MagickSizeType) length)
+      {
+        cache_info->pixels=(PixelPacket *) ResizeMagickMemory(
+          cache_info->pixels,length);
+        cache_info->length=(MagickSizeType) length;
+      }
+  if (cache_info->pixels == (void *) NULL)
+    return((PixelPacket *) NULL);
+  cache_info->indexes=(IndexPacket *) NULL;
+  if ((image->storage_class == PseudoClass) ||
+      (image->colorspace == CMYKColorspace))
+    cache_info->indexes=(IndexPacket *) (cache_info->pixels+number_pixels);
+  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_indexes_from_handler=GetVirtualIndexesFromStream;
+  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_indexes_from_handler=
+    GetAuthenticIndexesFromStream;
+  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 he wStreamImage() 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)
+{
+  RectangleInfo
+    extract_info;
+
+  size_t
+    length,
+    packet_size;
+
+  ssize_t
+    count;
+
+  StreamInfo
+    *stream_info;
+
+  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(long); break;
+    case QuantumPixel: packet_size=sizeof(Quantum); break;
+    case ShortPixel: packet_size=sizeof(unsigned short); break;
+  }
+  packet_size*=strlen(stream_info->map);
+  length=packet_size*image->columns;
+  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 (pixels == (unsigned char *) NULL)
+        return(0);
+      stream_info->image=image;
+      write_info=CloneImageInfo(stream_info->image_info);
+      (void) SetImageInfo(write_info,MagickFalse,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 >= (long) (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 long
+    i,
+    x;
+
+  register const PixelPacket
+    *p;
+
+  register IndexPacket
+    *indexes;
+
+  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 < (long) 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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->blue);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->red);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->blue);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->red);
+            *q++=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+              break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->blue);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->red);
+            *q++=ScaleQuantumToChar((Quantum) 0);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->red);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->blue);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->red);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->blue);
+            *q++=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(p->red);
+            *q++=ScaleQuantumToChar(p->green);
+            *q++=ScaleQuantumToChar(p->blue);
+            *q++=ScaleQuantumToChar((Quantum) 0);
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToChar(p->red);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToChar(p->green);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToChar(p->blue);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToChar((Quantum) (QuantumRange-p->opacity));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToChar(p->opacity);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToChar(indexes[x]);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToChar(PixelIntensityToQuantum(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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*((Quantum) (QuantumRange-p->opacity)))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*PixelIntensityToQuantum(p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*((Quantum) (QuantumRange-p->opacity)))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(double) ((QuantumScale*p->red)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(double) ((QuantumScale*p->green)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(double) ((QuantumScale*p->blue)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(double) ((QuantumScale*((Quantum) (QuantumRange-
+                p->opacity)))*quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(double) ((QuantumScale*p->opacity)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(double) ((QuantumScale*indexes[x])*quantum_info->scale+
+                  quantum_info->minimum);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(double) ((QuantumScale*PixelIntensityToQuantum(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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*(Quantum) (QuantumRange-p->opacity))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*PixelIntensityToQuantum(p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*((Quantum) (QuantumRange-p->opacity)))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*p->red)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->green)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+              quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(float) ((QuantumScale*p->red)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(float) ((QuantumScale*p->green)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(float) ((QuantumScale*p->blue)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(float) ((QuantumScale*((Quantum) (QuantumRange-
+                p->opacity)))*quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(float) ((QuantumScale*p->opacity)*quantum_info->scale+
+                quantum_info->minimum);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(float) ((QuantumScale*indexes[x])*quantum_info->scale+
+                  quantum_info->minimum);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(float) ((QuantumScale*PixelIntensityToQuantum(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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            *q++=(unsigned int) ScaleQuantumToLong((Quantum) (QuantumRange-
+              p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(
+              PixelIntensityToQuantum(p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            *q++=(unsigned int) ScaleQuantumToLong((Quantum)
+              (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(p->red);
+            *q++=(unsigned int) ScaleQuantumToLong(p->green);
+            *q++=(unsigned int) ScaleQuantumToLong(p->blue);
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(p->red);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(p->green);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(p->blue);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong((Quantum) (QuantumRange-
+                p->opacity));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(p->opacity);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(unsigned int) ScaleQuantumToLong(indexes[x]);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(unsigned int)
+                ScaleQuantumToLong(PixelIntensityToQuantum(p));
+              break;
+            }
+            default:
+              *q=0;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register unsigned long
+        *q;
+
+      q=(unsigned long *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->blue);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->red);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->blue);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->red);
+            *q++=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->blue);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->red);
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(PixelIntensityToQuantum(p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->red);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->blue);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->red);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->blue);
+            *q++=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(p->red);
+            *q++=ScaleQuantumToLong(p->green);
+            *q++=ScaleQuantumToLong(p->blue);
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToLong(p->red);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToLong(p->green);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToLong(p->blue);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToLong((Quantum) (QuantumRange-p->opacity));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToLong(p->opacity);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToLong(indexes[x]);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToLong(PixelIntensityToQuantum(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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->blue;
+            *q++=p->green;
+            *q++=p->red;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->blue;
+            *q++=p->green;
+            *q++=p->red;
+            *q++=(Quantum) (QuantumRange-p->opacity);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->blue;
+            *q++=p->green;
+            *q++=p->red;
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=PixelIntensityToQuantum(p);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->red;
+            *q++=p->green;
+            *q++=p->blue;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->red;
+            *q++=p->green;
+            *q++=p->blue;
+            *q++=(Quantum) (QuantumRange-p->opacity);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=p->red;
+            *q++=p->green;
+            *q++=p->blue;
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=(Quantum) 0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=p->red;
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=p->green;
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=p->blue;
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(Quantum) (QuantumRange-p->opacity);
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=p->opacity;
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=indexes[x];
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(PixelIntensityToQuantum(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 PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->blue);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->red);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->blue);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->red);
+            *q++=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+            if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->blue);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->red);
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(PixelIntensityToQuantum(p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->red);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->blue);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->red);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->blue);
+            *q++=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const PixelPacket *) NULL)
+            break;
+          for (x=0; x < (long) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(p->red);
+            *q++=ScaleQuantumToShort(p->green);
+            *q++=ScaleQuantumToShort(p->blue);
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const PixelPacket *) NULL)
+        break;
+      indexes=GetAuthenticIndexQueue(image);
+      for (x=0; x < (long) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (long) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToShort(p->red);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToShort(p->green);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToShort(p->blue);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToShort((Quantum) (QuantumRange-p->opacity));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToShort(p->opacity);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToShort(indexes[x]);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToShort(PixelIntensityToQuantum(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/magick/stream.h b/magick/stream.h
new file mode 100644
index 0000000..631f79f
--- /dev/null
+++ b/magick/stream.h
@@ -0,0 +1,38 @@
+/*
+  Copyright 1999-2009 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/magick/string.c b/magick/string.c
new file mode 100644
index 0000000..beca1aa
--- /dev/null
+++ b/magick/string.c
@@ -0,0 +1,2491 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/property.h"
+#include "magick/resource_.h"
+#include "magick/signature-private.h"
+#include "magick/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);
+  destination=(char *) NULL;
+  if (~length >= MaxTextExtent)
+    destination=(char *) AcquireQuantumMemory(length+MaxTextExtent,
+      sizeof(*destination));
+  if (destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  *destination='\0';
+  if (source != (char *) NULL)
+    (void) CopyMagickString(destination,source,(length+1)*sizeof(*destination));
+  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)
+        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");
+  (void) CopyMagickString(*destination,source,(length+1)*sizeof(*destination));
+  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) CopyMagickMemory(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
+    length,
+    source_length;
+
+  assert(destination != (char **) NULL);
+  if (source == (const char *) NULL)
+    return(MagickTrue);
+  if (*destination == (char *) NULL)
+    {
+      *destination=AcquireString(source);
+      return(MagickTrue);
+    }
+  length=strlen(*destination);
+  source_length=strlen(source);
+  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");
+  (void) ConcatenateMagickString(*destination,source,(length+1)*
+    sizeof(*destination));
+  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) CopyMagickMemory(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) MagickSeek(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)
+    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) CopyMagickMemory(string,map,length);
+      (void) UnmapBlob(map,length);
+    }
+  else
+    {
+      register size_t
+        i;
+
+      ssize_t
+        count;
+
+      (void) MagickSeek(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) CopyMagickString(destination,source,(length+1)*sizeof(*destination));
+  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 long
+    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)
+    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,
+%  14kb, 234mb, 2.7gb, or 3.0tb.  Scaling is done by repetitively dividing by
+%  1024.
+%
+%  The format of the FormatMagickSize method is:
+%
+%      long FormatMagickSize(const MagickSizeType size,char *format)
+%
+%  A description of each parameter follows:
+%
+%    o size:  convert this size to a human readable format.
+%
+%    o format:  human readable format.
+%
+*/
+MagickExport long FormatMagickSize(const MagickSizeType size,char *format)
+{
+  double
+    length;
+
+  long
+    count;
+
+  register long
+    i,
+    j;
+
+  static const char
+    *units[] = { "b", "kb", "mb", "gb", "tb", "pb", "eb", (char *) NULL };
+
+#if defined(_MSC_VER) && (_MSC_VER == 1200)
+  length=(double) ((MagickOffsetType) size);
+#else
+  length=(double) size;
+#endif
+  for (i=0; (length >= 1024.0) && (units[i+1] != (const char *) NULL); i++)
+    length/=1024.0;
+  for (j=2; j < 10; j++)
+  {
+    count=FormatMagickString(format,MaxTextExtent,"%.*g%s",(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 S t r i n g                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatMagickString() prints formatted output of a variable argument list.
+%
+%  The format of the FormatMagickString method is:
+%
+%      long FormatMagickString(char *string,const size_t length,
+%        const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o string:  FormatMagickString() 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 long FormatMagickStringList(char *string,const size_t length,
+  const char *format,va_list operands)
+{
+  int
+    n;
+
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(string,length,format,operands);
+#else
+  n=vsprintf(string,format,operands);
+#endif
+  if (n < 0)
+    string[length-1]='\0';
+  return((long) n);
+}
+
+MagickExport long FormatMagickString(char *string,const size_t length,
+  const char *format,...)
+{
+  long
+    n;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  n=(long) FormatMagickStringList(string,length,format,operands);
+  va_end(operands);
+  return(n);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  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:
+%
+%      long 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 long FormatMagickTime(const time_t time,const size_t length,
+  char *timestamp)
+{
+  long
+    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=FormatMagickString(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:
+%
+%      long 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 long 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((long) strcasecmp(p,q));
+#else
+  {
+    register unsigned char
+      c,
+      d;
+
+    for ( ; ; )
+    {
+      c=(unsigned char) *p;
+      d=(unsigned char) *q;
+      if ((c == '\0') || (AsciiMap[c] != AsciiMap[d]))
+        break;
+      p++;
+      q++;
+    }
+    return((long) AsciiMap[c]-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:
+%
+%      long 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 & q.
+%
+*/
+MagickExport long 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((long) strncasecmp(p,q,length));
+#else
+  {
+    register size_t
+      n;
+
+    register unsigned char
+      c,
+      d;
+
+    for (n=length; n != 0; n--)
+    {
+      c=(unsigned char) *p;
+      d=(unsigned char) *q;
+      if (AsciiMap[c] != AsciiMap[d])
+        return(AsciiMap[c]-AsciiMap[d]);
+      if (c == '\0')
+        return(0L);
+      p++;
+      q++;
+    }
+    return(0L);
+  }
+#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) fprintf(file,"0x%08lx: ",(unsigned long) (0x14*i));
+    for (j=1; j <= MagickMin(string_info->length-i,0x14); j++)
+    {
+      (void) fprintf(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) CopyMagickMemory(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) CopyMagickMemory(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) CopyMagickMemory(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)
+    string=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*string));
+  if (string != (char *) NULL)
+    (void) CopyMagickString(string,(char *) string_info->datum,
+      (length+1)*sizeof(*string));
+  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 long
+    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++;
+    (*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 < (long) *argc; i++)
+  {
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    q=p;
+    if (*q == '"')
+      {
+        p++;
+        for (q++; (*q != '"') && (*q != '\0'); q++) ;
+      }
+    else
+      if (*q == '\'')
+        {
+          for (q++; (*q != '\'') && (*q != '\0'); q++) ;
+          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) CopyMagickString(argv[i],p,(size_t) (q-p+1));
+    p=q;
+    while ((isspace((int) ((unsigned char) *p)) == 0) && (*p != '\0'))
+      p++;
+  }
+  argv[i]=(char *) NULL;
+  return(argv);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  S t r i n g T o D o u b l e                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringToDouble() converts a text string to a double.  If the string contains
+%  a percent sign (e.g. 50%) that percentage of the interval is returned.
+%
+%  The format of the StringToDouble method is:
+%
+%      double StringToDouble(const char *string,const double interval)
+%
+%  A description of each parameter follows:
+%
+%    o string:  Specifies the string representing a value.
+%
+%    o interval:  Specifies the interval; used for obtaining a percentage.
+%
+*/
+MagickExport double StringToDouble(const char *string,const double interval)
+{
+  char
+    *q;
+
+  double
+    value;
+
+  assert(string != (char *) NULL);
+  value=strtod(string,&q);
+  switch (tolower((int) ((unsigned char) *q)))
+  {
+    case '%': value*=pow(1024.0,0)*interval/100.0; break;
+    case 'k': value*=pow(1024.0,1); break;
+    case 'm': value*=pow(1024.0,2); break;
+    case 'g': value*=pow(1024.0,3); break;
+    case 't': value*=pow(1024.0,4); break;
+    case 'p': value*=pow(1024.0,5); break;
+    case 'e': value*=pow(1024.0,6); break;
+    case 'z': value*=pow(1024.0,7); break;
+    case 'y': value*=pow(1024.0,8); break;
+    default:  break;
+  }
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long
+    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 < (long) 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 list:  Method StringToList returns the string list unless an error
+%      occurs, otherwise NULL.
+%
+%    o text:  Specifies the string to segment into a list.
+%
+*/
+MagickExport char **StringToList(const char *text)
+{
+  char
+    **textlist;
+
+  register const char
+    *p;
+
+  register long
+    i;
+
+  unsigned long
+    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 < (long) 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) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
+        if (*q == '\r')
+          q++;
+        p=q+1;
+      }
+    }
+  else
+    {
+      char
+        hex_string[MaxTextExtent];
+
+      register char
+        *q;
+
+      register long
+        j;
+
+      /*
+        Convert string to a HEX list.
+      */
+      lines=(unsigned long) (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 < (long) lines; i++)
+      {
+        textlist[i]=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
+          sizeof(*textlist));
+        if (textlist[i] == (char *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
+        (void) FormatMagickString(textlist[i],MaxTextExtent,"0x%08lx: ",0x14*i);
+        q=textlist[i]+strlen(textlist[i]);
+        for (j=1; j <= (long) MagickMin(strlen(p),0x14); j++)
+        {
+          (void) FormatMagickString(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 <= (long) 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) CopyMagickMemory(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 buffer, replacing the
+%  buffer with the substituted version. Buffer must be allocate from the heap.
+%
+%  The format of the SubstituteString method is:
+%
+%      MagickBooleanType SubstituteString(char **buffer,const char *search,
+%        const char *replace)
+%
+%  A description of each parameter follows:
+%
+%    o buffer: the buffer to perform replacements on. Replaced with new
+%      allocation if a replacement is made.
+%
+%    o search: String to search for.
+%
+%    o replace: Replacement string.
+%
+*/
+MagickExport MagickBooleanType SubstituteString(char **buffer,
+  const char *search,const char *replace)
+{
+  char
+    *result;
+
+  const char
+    *match,
+    *source;
+
+  MagickOffsetType
+    destination_offset;
+
+  size_t
+    copy_length,
+    length,
+    replace_length,
+    result_length,
+    search_length;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(buffer != (char **) NULL);
+  assert(*buffer != (char *) NULL);
+  assert(search != (const char *) NULL);
+  assert(replace != (const char *) NULL);
+  if (strcmp(search,replace) == 0)
+    return(MagickTrue);
+  source=(*buffer);
+  match=strstr(source,search);
+  if (match == (char *) NULL)
+    return(MagickFalse);
+  result=(char *) NULL;
+  length=strlen(source);
+  if (~length >= MaxTextExtent)
+    result=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*result));
+  if (result == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  *result='\0';
+  result_length=0;
+  destination_offset=0;
+  replace_length=strlen(replace);
+  for (search_length=strlen(search); match != (char *) NULL; )
+  {
+    /*
+      Copy portion before match.
+    */
+    copy_length=(size_t) (match-source);
+    if (copy_length != 0)
+      {
+        result_length+=copy_length;
+        if ((result_length+MaxTextExtent) >= length)
+          {
+            length+=copy_length;
+            result=(char *) ResizeQuantumMemory(result,length+MaxTextExtent,
+              sizeof(*result));
+            if (result == (char *) NULL)
+              ThrowFatalException(ResourceLimitFatalError,
+                "UnableToAcquireString");
+          }
+        (void) CopyMagickString(result+destination_offset,source,copy_length+1);
+        destination_offset+=copy_length;
+      }
+    /*
+      Copy replacement.
+    */
+    result_length+=replace_length;
+    if ((result_length+MaxTextExtent) >= length)
+      {
+        length+=replace_length;
+        result=(char *) ResizeQuantumMemory(result,length+MaxTextExtent,
+          sizeof(*result));
+        if (result == (char *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+      }
+    (void) ConcatenateMagickString(result+destination_offset,replace,length);
+    destination_offset+=replace_length;
+    /*
+      Find next match.
+    */
+    source=match;
+    source+=search_length;
+    match=strstr(source,search);
+  }
+  /*
+    Copy remaining string.
+  */
+  copy_length=strlen(source);
+  result_length+=copy_length;
+  if ((result_length+MaxTextExtent) >= length)
+    {
+      length+=copy_length;
+      result=(char *) ResizeQuantumMemory(result,length+MaxTextExtent,
+        sizeof(*result));
+      if (result == (char *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+    }
+  (void) ConcatenateMagickString(result+destination_offset,source,(size_t)
+    (length+MaxTextExtent-destination_offset));
+  (void) RelinquishMagickMemory(*buffer);
+  *buffer=result;
+  return(MagickTrue);
+}
diff --git a/magick/string_.h b/magick/string_.h
new file mode 100644
index 0000000..be346fb
--- /dev/null
+++ b/magick/string_.h
@@ -0,0 +1,115 @@
+/*
+  Copyright 1999-2009 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 "magick/exception.h"
+
+typedef struct _StringInfo
+{
+  char
+    path[MaxTextExtent];
+
+  unsigned char
+    *datum;
+
+  size_t
+    length;
+
+  unsigned long
+    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 double
+  StringToDouble(const char *,const double);
+
+extern MagickExport long
+  FormatMagickSize(const MagickSizeType,char *),
+  FormatMagickString(char *,const size_t,const char *,...)
+    magick_attribute((format (printf,3,4))),
+  FormatMagickStringList(char *,const size_t,const char *,va_list)
+    magick_attribute((format (printf,3,0))),
+  FormatMagickTime(const time_t,const size_t,char *),
+  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 int
+  CompareStringInfo(const StringInfo *,const StringInfo *);
+
+extern MagickExport size_t
+  ConcatenateMagickString(char *,const char *,const size_t),
+  CopyMagickString(char *,const char *,const size_t),
+  GetStringInfoLength(const StringInfo *);
+
+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 *),
+  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/magick/studio.h b/magick/studio.h
new file mode 100644
index 0000000..c43512b
--- /dev/null
+++ b/magick/studio.h
@@ -0,0 +1,450 @@
+/*
+  Copyright 1999-2009 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(__CYGWIN32__)
+#  if !defined(__CYGWIN__)
+#    define __CYGWIN__ __CYGWIN32__
+#  endif
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#  if !defined(__WINDOWS__)
+#    if defined(_WIN32)
+#      define __WINDOWS__ _WIN32
+#    else
+#      if defined(WIN32)
+#        define __WINDOWS__ WIN32
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined(_WIN64) || defined(WIN64)
+#  if !defined(__WINDOWS__)
+#    if defined(_WIN64)
+#      define __WINDOWS__ _WIN64
+#    else
+#      if defined(WIN64)
+#        define __WINDOWS__ WIN64
+#      endif
+#    endif
+#  endif
+#endif
+
+#if !defined(vms) && !defined(macintosh) && !defined(__WINDOWS__)
+# define MAGICKCORE_POSIX_SUPPORT
+#endif
+
+#define MAGICKCORE_IMPLEMENTATION  1
+
+#if !defined(_MAGICKCORE_CONFIG_H)
+# define _MAGICKCORE_CONFIG_H
+# if !defined(vms) && !defined(macintosh)
+#  include "magick/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(__cplusplus) || defined(c_plusplus)
+#  undef inline
+# endif
+#if defined(_magickcore_restrict) && !defined(__restrict)
+# define __restrict _magickcore_restrict
+#endif
+#endif
+
+#if defined(MAGICKCORE_NAMESPACE_PREFIX)
+# include "magick/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(__WINDOWS__)
+# 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(__WINDOWS__) && defined(_DEBUG)
+#define _CRTDBG_MAP_ALLOC
+#endif
+#include <stdlib.h>
+#if !defined(__WINDOWS__)
+# include <unistd.h>
+#else
+# include <direct.h>
+# if !defined(MAGICKCORE_HAVE_STRERROR)
+#  define HAVE_STRERROR
+# endif
+#endif
+
+#if defined(MAGICKCORE_HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+#include <string.h>
+#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_PTHREAD)
+# include <pthread.h>
+#elif defined(__WINDOWS__)
+#  define MAGICKORE_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(_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(magick_attribute)
+#  if !defined(__GNUC__)
+#    define magick_attribute(x)  /* nothing */
+#  else
+#    define magick_attribute  __attribute__
+#  endif
+#endif
+
+#if !defined(magick_unused)
+#  if defined(__GNUC__)
+#     define magick_unused(x)  magick_unused_ ## x __attribute__((unused))
+#  elif defined(__LCLINT__)
+#    define magick_unused(x) /*@unused@*/ x
+#  else
+#    define magick_unused(x) x
+#  endif
+#endif
+
+#if defined(__WINDOWS__) || 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 "magick/magick-type.h"
+# if !defined(__WINDOWS__)
+#  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 "magick/magick-type.h"
+#endif
+
+#if defined(S_IRUSR) && defined(S_IWUSR)
+# define S_MODE (S_IRUSR | S_IWUSR)
+#elif defined (__WINDOWS__)
+# define S_MODE (_S_IREAD | _S_IWRITE)
+#else
+# define S_MODE  0600
+#endif
+
+#if defined(__WINDOWS__)
+# include "magick/nt-base.h"
+#endif
+#if defined(macintosh)
+# include "magick/mac.h"
+#endif
+#if defined(vms)
+# include "magick/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(__WINDOWS__)
+#  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(MAGICKCORE_LTDL_DELEGATE) || (defined(__WINDOWS__) && defined(_DLL) && !defined(_LIB))
+#  define MAGICKCORE_MODULES_SUPPORT
+#endif
+
+#if defined(_MAGICKMOD_)
+# undef MAGICKCORE_BUILD_MODULES
+# define MAGICKCORE_BUILD_MODULES
+#endif
+
+/*
+  I/O defines.
+*/
+#if defined(__WINDOWS__) && !defined(Windows95) && !defined(__BORLANDC__)
+#define MagickSeek(file,offset,whence)  _lseeki64(file,offset,whence)
+#define MagickTell(file)  _telli64(file)
+#else
+#define MagickSeek(file,offset,whence)  lseek(file,offset,whence)
+#define MagickTell(file) tell(file)
+#endif
+
+/*
+  Magick defines.
+*/
+#define Swap(x,y) ((x)^=(y), (y)^=(x), (x)^=(y))
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/thread-private.h b/magick/thread-private.h
new file mode 100644
index 0000000..2bec784
--- /dev/null
+++ b/magick/thread-private.h
@@ -0,0 +1,118 @@
+/*
+  Copyright 1999-2009 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 <magick/thread_.h>
+
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  typedef pthread_mutex_t MagickMutexType;
+#elif defined(__WINDOWS__)
+  typedef CRITICAL_SECTION MagickMutexType;
+#else
+  typedef unsigned long MagickMutexType;
+#endif
+
+static inline MagickThreadType GetMagickThreadId(void)
+{
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  return(pthread_self());
+#elif defined(__WINDOWS__)
+  return(GetCurrentThreadId());
+#else
+  return(getpid());
+#endif
+}
+
+static inline unsigned long GetMagickThreadSignature(void)
+{
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  {
+    union
+    {
+      pthread_t
+        id;
+
+      unsigned long
+        signature;
+    } magick_thread;
+
+    magick_thread.signature=0UL;
+    magick_thread.id=pthread_self();
+    return(magick_thread.signature);
+  }
+#elif defined(__WINDOWS__)
+  return((unsigned long) GetCurrentThreadId());
+#else
+  return((unsigned long) getpid());
+#endif
+}
+
+static inline MagickBooleanType IsMagickThreadEqual(const MagickThreadType id)
+{
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+  if (pthread_equal(id,pthread_self()) != 0)
+    return(MagickTrue);
+#elif defined(__WINDOWS__)
+  if (id == GetCurrentThreadId())
+    return(MagickTrue);
+#else
+  if (id == getpid())
+    return(MagickTrue);
+#endif
+  return(MagickFalse);
+}
+
+/*
+  Lightweight OpenMP methods.
+*/
+static inline unsigned long GetOpenMPMaximumThreads(void)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  return((unsigned long) omp_get_max_threads());
+#endif
+  return(1UL);
+}
+
+static inline long GetOpenMPThreadId(void)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  return(omp_get_thread_num());
+#else
+  return(0);
+#endif
+}
+
+static inline void SetOpenMPMaximumThreads(const unsigned long threads)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  omp_set_num_threads(threads);
+#else
+  (void) threads;
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/thread.c b/magick/thread.c
new file mode 100644
index 0000000..56f2cd5
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/memory_.h"
+#include "magick/thread_.h"
+#include "magick/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_HAVE_PTHREAD)
+  return(pthread_key_create(key,NULL) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKORE_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_HAVE_PTHREAD)
+  return(pthread_key_delete(key) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKORE_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_HAVE_PTHREAD)
+  return(pthread_getspecific(key));
+#elif defined(MAGICKORE_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_HAVE_PTHREAD)
+  return(pthread_setspecific(key,value) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+  return(TlsSetValue(key,(void *) value) != 0 ? MagickTrue : MagickFalse);
+#else
+  *key=(unsigned long) value;
+  return(MagickTrue);
+#endif
+}
diff --git a/magick/thread_.h b/magick/thread_.h
new file mode 100644
index 0000000..1003a66
--- /dev/null
+++ b/magick/thread_.h
@@ -0,0 +1,53 @@
+/*
+  Copyright 1999-2009 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_HAVE_PTHREAD)
+typedef pthread_t MagickThreadType;
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+typedef DWORD MagickThreadType;
+#else
+typedef pid_t MagickThreadType;
+#endif
+
+#if defined(MAGICKCORE_HAVE_PTHREAD)
+typedef pthread_key_t MagickThreadKey;
+#elif defined(MAGICKORE_HAVE_WINTHREADS)
+typedef DWORD MagickThreadKey;
+#else
+typedef unsigned long *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/magick/threshold.c b/magick/threshold.c
new file mode 100644
index 0000000..88c78e4
--- /dev/null
+++ b/magick/threshold.c
@@ -0,0 +1,1908 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%       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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace.h"
+#include "magick/configure.h"
+#include "magick/constitute.h"
+#include "magick/decorate.h"
+#include "magick/draw.h"
+#include "magick/enhance.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/effect.h"
+#include "magick/fx.h"
+#include "magick/gem.h"
+#include "magick/geometry.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/montage.h"
+#include "magick/pixel-private.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/random_.h"
+#include "magick/random-private.h"
+#include "magick/resize.h"
+#include "magick/resource_.h"
+#include "magick/segment.h"
+#include "magick/shear.h"
+#include "magick/signature-private.h"
+#include "magick/string_.h"
+#include "magick/transform.h"
+#include "magick/threshold.h"
+#include "magick/option.h"
+#include "magick/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ThresholdsFilename  "thresholds.xml"
+
+/*
+  Typedef declarations.
+*/
+struct _ThresholdMap
+{
+  char
+    *map_id,
+    *description;
+
+  unsigned long
+    width,
+    height;
+
+  long
+    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 unsigned long width,const unsigned long height,
+%        const long 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 unsigned long width,const unsigned long height,const long offset,
+  ExceptionInfo *exception)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  Image
+    *threshold_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    zero;
+
+  MagickRealType
+    number_pixels;
+
+  CacheView
+    *image_view,
+    *threshold_view;
+
+  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 < width) || (image->rows < height))
+    ThrowImageException(OptionError,"ImageSmallerThanRadius");
+  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;
+  GetMagickPixelPacket(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 < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict threshold_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-height/2L,
+      image->columns+width,height,exception);
+    q=GetCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    threshold_indexes=GetCacheViewAuthenticIndexQueue(threshold_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      long
+        v;
+
+      MagickPixelPacket
+        mean,
+        pixel;
+
+      register const PixelPacket
+        *r;
+
+      register long
+        u;
+
+      pixel=zero;
+      mean=zero;
+      r=p;
+      for (v=0; v < (long) height; v++)
+      {
+        for (u=0; u < (long) width; u++)
+        {
+          pixel.red+=r[u].red;
+          pixel.green+=r[u].green;
+          pixel.blue+=r[u].blue;
+          pixel.opacity+=r[u].opacity;
+          if (image->colorspace == CMYKColorspace)
+            pixel.index=(MagickRealType) indexes[x+(r-p)+u];
+        }
+        r+=image->columns+width;
+      }
+      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.opacity=(MagickRealType) (pixel.opacity/number_pixels+offset);
+      if (image->colorspace == CMYKColorspace)
+        mean.index=(MagickRealType) (pixel.index/number_pixels+offset);
+      q->red=(Quantum) (((MagickRealType) q->red <= mean.red) ?
+        0 : QuantumRange);
+      q->green=(Quantum) (((MagickRealType) q->green <= mean.green) ?
+        0 : QuantumRange);
+      q->blue=(Quantum) (((MagickRealType) q->blue <= mean.blue) ?
+        0 : QuantumRange);
+      q->opacity=(Quantum) (((MagickRealType) q->opacity <= mean.opacity) ?
+        0 : QuantumRange);
+      if (image->colorspace == CMYKColorspace)
+        threshold_indexes[x]=(IndexPacket) (((MagickRealType)
+          threshold_indexes[x] <= mean.index) ? 0 : QuantumRange);
+      p++;
+      q++;
+    }
+    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"
+
+  ExceptionInfo
+    *exception;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *image_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (channel == DefaultChannels)
+      {
+        for (x=0; x < (long) image->columns; x++)
+        {
+          q->red=(Quantum) ((MagickRealType) PixelIntensityToQuantum(q) <=
+            threshold ? 0 : QuantumRange);
+          q->green=q->red;
+          q->blue=q->red;
+          q++;
+        }
+      }
+    else
+      for (x=0; x < (long) image->columns; x++)
+      {
+        if ((channel & RedChannel) != 0)
+          q->red=(Quantum) ((MagickRealType) q->red <= threshold ? 0 :
+            QuantumRange);
+        if ((channel & GreenChannel) != 0)
+          q->green=(Quantum) ((MagickRealType) q->green <= threshold ? 0 :
+            QuantumRange);
+        if ((channel & BlueChannel) != 0)
+          q->blue=(Quantum) ((MagickRealType) q->blue <= threshold ? 0 :
+            QuantumRange);
+        if ((channel & OpacityChannel) != 0)
+          {
+            if (image->matte == MagickFalse)
+              q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold ?
+                0 : QuantumRange);
+            else
+              q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold ?
+                OpaqueOpacity : TransparentOpacity);
+          }
+        if (((channel & IndexChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          indexes[x]=(IndexPacket) ((MagickRealType) indexes[x] <= threshold ?
+            0 : QuantumRange);
+        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_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 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"
+
+  GeometryInfo
+    geometry_info;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    threshold;
+
+  MagickStatusType
+    flags;
+
+  CacheView
+    *image_view;
+
+  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);
+  GetMagickPixelPacket(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.opacity=geometry_info.psi;
+  if ((flags & PsiValue) == 0)
+    threshold.opacity=threshold.red;
+  threshold.index=geometry_info.chi;
+  if ((flags & ChiValue) == 0)
+    threshold.index=threshold.red;
+  if ((flags & PercentValue) != 0)
+    {
+      threshold.red*=(QuantumRange/100.0);
+      threshold.green*=(QuantumRange/100.0);
+      threshold.blue*=(QuantumRange/100.0);
+      threshold.opacity*=(QuantumRange/100.0);
+      threshold.index*=(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,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (channel == DefaultChannels)
+      for (x=0; x < (long) image->columns; x++)
+      {
+        if ((MagickRealType) q->red < threshold.red)
+          q->red=(Quantum) 0;
+        if ((MagickRealType) q->green < threshold.green)
+          q->green=(Quantum) 0;
+        if ((MagickRealType) q->blue < threshold.blue)
+          q->blue=(Quantum) 0;
+        if ((image->colorspace == CMYKColorspace) &&
+            ((MagickRealType) indexes[x] < threshold.index))
+          indexes[x]=(Quantum) 0;
+        q++;
+      }
+    else
+      for (x=0; x < (long) image->columns; x++)
+      {
+        if (((channel & RedChannel) != 0) &&
+            ((MagickRealType) q->red < threshold.red))
+          q->red=(Quantum) 0;
+        if (((channel & GreenChannel) != 0) &&
+            ((MagickRealType) q->green < threshold.green))
+          q->green=(Quantum) 0;
+        if (((channel & BlueChannel) != 0) &&
+            ((MagickRealType) q->blue < threshold.blue))
+          q->blue=(Quantum) 0;
+        if (((channel & OpacityChannel) != 0) &&
+            ((MagickRealType) q->opacity < threshold.opacity))
+          q->opacity=(Quantum) 0;
+        if (((channel & IndexChannel) != 0) &&
+            (image->colorspace == CMYKColorspace) &&
+            ((MagickRealType) indexes[x] < threshold.index))
+          indexes[x]=(Quantum) 0;
+        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_BlackThresholdImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,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 != (long *) NULL)
+    map->levels=(long *) 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 = (long *) 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 = (unsigned long) atoi(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 = (unsigned long) atoi(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 = atoi(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=(long *) AcquireQuantumMemory((size_t) map->width,map->height*
+    sizeof(*map->levels));
+  if ( map->levels == (long *)NULL )
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
+  { /* parse levels into integer array */
+    int i;
+    char *p;
+    for( i=0; i< (long) (map->width*map->height); i++) {
+      map->levels[i] = (int)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> %ld out of range, map \"%s\"",
+          map->levels[i], map_id);
+        thresholds = DestroyXMLTree(thresholds);
+        map = DestroyThresholdMap(map);
+        return(map);
+      }
+      content = p;
+    }
+    value=(double) strtol(content,&p,10);
+    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) fprintf(file,"%-16s %-12s %s\n", "Map", "Alias", "Description");
+  (void) fprintf(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) fprintf(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) fprintf(file, "\n   Threshold Maps for Ordered Dither Operations\n");
+
+  while ( ( option=(const StringInfo *) GetNextValueInLinkedList(options) )
+          != (const StringInfo *) NULL)
+  {
+    (void) fprintf(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 D i t h e r I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OrderedDitherImage() uses the ordered dithering technique of reducing color
+%  images to monochrome using positional information to retain as much
+%  information as possible.
+%
+%  WARNING: This function is deprecated, and is now just a call to
+%  the more more powerful OrderedPosterizeImage(); function.
+%
+%  The format of the OrderedDitherImage method is:
+%
+%      MagickBooleanType OrderedDitherImage(Image *image)
+%      MagickBooleanType OrderedDitherImageChannel(Image *image,
+%        const ChannelType channel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel or channels to be thresholded.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType OrderedDitherImage(Image *image)
+{
+  MagickBooleanType
+    status;
+
+  status=OrderedDitherImageChannel(image,DefaultChannels,&image->exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType OrderedDitherImageChannel(Image *image,
+ const ChannelType channel,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  /*
+    Call the augumented function OrderedPosterizeImage()
+  */
+  status=OrderedPosterizeImageChannel(image,channel,"o8x8",exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     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 equivelent 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"
+
+  long
+    progress,
+    y;
+
+  LongPixelPacket
+    levels;
+
+  MagickBooleanType
+    status;
+
+  ThresholdMap
+    *map;
+
+  CacheView
+    *image_view;
+
+  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)
+        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 seperated arguments
+     Default to 2, the single value given, or individual channel values
+  */
+#if 1
+  { /* parse directly as a comma seperated list of integers */
+    char *p;
+
+    p = strchr((char *) threshold_map,',');
+    if ( p != (char *)NULL && isdigit((int) ((unsigned char) *(++p))) )
+      levels.index = (unsigned long) strtol(p, &p, 10);
+    else
+      levels.index = 2;
+
+    levels.red     = ((channel & RedChannel  )   != 0) ? levels.index : 0;
+    levels.green   = ((channel & GreenChannel)   != 0) ? levels.index : 0;
+    levels.blue    = ((channel & BlueChannel)    != 0) ? levels.index : 0;
+    levels.opacity = ((channel & OpacityChannel) != 0) ? levels.index : 0;
+    levels.index   = ((channel & IndexChannel)   != 0
+            && (image->colorspace == CMYKColorspace)) ? levels.index : 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 long) strtol(p, &p, 10),   (void)(*p == ',' && p++);
+      if ((channel & GreenChannel) != 0)
+        levels.green = (unsigned long) strtol(p, &p, 10), (void)(*p == ',' && p++);
+      if ((channel & BlueChannel) != 0)
+        levels.blue = (unsigned long) strtol(p, &p, 10),  (void)(*p == ',' && p++);
+      if ((channel & IndexChannel) != 0 && image->colorspace == CMYKColorspace)
+        levels.index=(unsigned long) strtol(p, &p, 10), (void)(*p == ',' && p++);
+      if ((channel & OpacityChannel) != 0)
+        levels.opacity = (unsigned long) strtol(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.opacity
+   * A simpler way is needed, probably converting geometry to a temporary
+   * array, then using channel to advance the index into long pixel packet.
+   */
+#endif
+
+#if 0
+printf("DEBUG levels  r=%ld g=%ld b=%ld a=%ld i=%ld\n",
+     levels.red, levels.green, levels.blue, levels.opacity, levels.index);
+#endif
+
+  { /* Do the posterized ordered dithering of the image */
+    int
+      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.opacity = levels.opacity ? levels.opacity-1 : 0;
+    levels.index   = levels.index   ? levels.index-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 < (long) image->rows; y++)
+    {
+      register IndexPacket
+        *__restrict indexes;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      if (status == MagickFalse)
+        continue;
+      q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+      if (q == (PixelPacket *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      indexes=GetCacheViewAuthenticIndexQueue(image_view);
+      for (x=0; x < (long) image->columns; x++)
+      {
+        register int
+          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) {
+          t = (int) (QuantumScale*q->red*(levels.red*d+1));
+          l = t/d;  t = t-l*d;
+          q->red=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.red);
+        }
+        if (levels.green) {
+          t = (int) (QuantumScale*q->green*(levels.green*d+1));
+          l = t/d;  t = t-l*d;
+          q->green=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.green);
+        }
+        if (levels.blue) {
+          t = (int) (QuantumScale*q->blue*(levels.blue*d+1));
+          l = t/d;  t = t-l*d;
+          q->blue=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.blue);
+        }
+        if (levels.opacity) {
+          t = (int) ((1.0-QuantumScale*q->opacity)*(levels.opacity*d+1));
+          l = t/d;  t = t-l*d;
+          q->opacity=(Quantum) ((1.0-l-(t >= threshold))*QuantumRange/
+            levels.opacity);
+        }
+        if (levels.index) {
+          t = (int) (QuantumScale*indexes[x]*(levels.index*d+1));
+          l = t/d;  t = t-l*d;
+          indexes[x]=(IndexPacket) ((l+(t>=threshold))*QuantumRange/
+            levels.index);
+        }
+        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_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"
+
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    threshold;
+
+  MagickRealType
+    min_threshold,
+    max_threshold;
+
+  RandomInfo
+    **random_info;
+
+  CacheView
+    *image_view;
+
+  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);
+  GetMagickPixelPacket(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 == AllChannels)
+    {
+      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 < (long) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register IndexPacket
+          *__restrict indexes;
+
+        register long
+          id,
+          x;
+
+        register PixelPacket
+          *__restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (PixelPacket *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        indexes=GetCacheViewAuthenticIndexQueue(image_view);
+        id=GetOpenMPThreadId();
+        for (x=0; x < (long) image->columns; x++)
+        {
+          IndexPacket
+            index;
+
+          MagickRealType
+            intensity;
+
+          intensity=(MagickRealType) PixelIntensityToQuantum(q);
+          if (intensity < min_threshold)
+            threshold.index=min_threshold;
+          else if (intensity > max_threshold)
+            threshold.index=max_threshold;
+          else
+            threshold.index=(MagickRealType)(QuantumRange*
+              GetPseudoRandomValue(random_info[id]));
+          index=(IndexPacket) (intensity <= threshold.index ? 0 : 1);
+          indexes[x]=index;
+          *q++=image->colormap[(long) index];
+        }
+        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 < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      id,
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    id=GetOpenMPThreadId();
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          if ((MagickRealType) q->red < min_threshold)
+            threshold.red=min_threshold;
+          else
+            if ((MagickRealType) q->red > max_threshold)
+              threshold.red=max_threshold;
+            else
+              threshold.red=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          if ((MagickRealType) q->green < min_threshold)
+            threshold.green=min_threshold;
+          else
+            if ((MagickRealType) q->green > max_threshold)
+              threshold.green=max_threshold;
+            else
+              threshold.green=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          if ((MagickRealType) q->blue < min_threshold)
+            threshold.blue=min_threshold;
+          else
+            if ((MagickRealType) q->blue > max_threshold)
+              threshold.blue=max_threshold;
+            else
+              threshold.blue=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          if ((MagickRealType) q->opacity < min_threshold)
+            threshold.opacity=min_threshold;
+          else
+            if ((MagickRealType) q->opacity > max_threshold)
+              threshold.opacity=max_threshold;
+            else
+              threshold.opacity=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if ((MagickRealType) indexes[x] < min_threshold)
+            threshold.index=min_threshold;
+          else
+            if ((MagickRealType) indexes[x] > max_threshold)
+              threshold.index=max_threshold;
+            else
+              threshold.index=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & RedChannel) != 0)
+        q->red=(Quantum) ((MagickRealType) q->red <= threshold.red ? 0 :
+          QuantumRange);
+      if ((channel & GreenChannel) != 0)
+        q->green=(Quantum) ((MagickRealType) q->green <= threshold.green ? 0 :
+          QuantumRange);
+      if ((channel & BlueChannel) != 0)
+        q->blue=(Quantum) ((MagickRealType) q->blue <= threshold.blue ? 0 :
+          QuantumRange);
+      if ((channel & OpacityChannel) != 0)
+        q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold.opacity ?
+          0 : QuantumRange);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        indexes[x]=(IndexPacket) ((MagickRealType) indexes[x] <=
+          threshold.index ? 0 : QuantumRange);
+      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_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 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"
+
+  GeometryInfo
+    geometry_info;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  MagickPixelPacket
+    threshold;
+
+  MagickStatusType
+    flags;
+
+  CacheView
+    *image_view;
+
+  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);
+  GetMagickPixelPacket(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.opacity=geometry_info.psi;
+  if ((flags & PsiValue) == 0)
+    threshold.opacity=threshold.red;
+  threshold.index=geometry_info.chi;
+  if ((flags & ChiValue) == 0)
+    threshold.index=threshold.red;
+  if ((flags & PercentValue) != 0)
+    {
+      threshold.red*=(QuantumRange/100.0);
+      threshold.green*=(QuantumRange/100.0);
+      threshold.blue*=(QuantumRange/100.0);
+      threshold.opacity*=(QuantumRange/100.0);
+      threshold.index*=(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,8) shared(progress,status)
+#endif
+  for (y=0; y < (long) image->rows; y++)
+  {
+    register IndexPacket
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if (((channel & RedChannel) != 0) &&
+          ((MagickRealType) q->red > threshold.red))
+        q->red=(Quantum) QuantumRange;
+      if (((channel & GreenChannel) != 0) &&
+          ((MagickRealType) q->green > threshold.green))
+        q->green=(Quantum) QuantumRange;
+      if (((channel & BlueChannel) != 0) &&
+          ((MagickRealType) q->blue > threshold.blue))
+        q->blue=(Quantum) QuantumRange;
+      if (((channel & OpacityChannel) != 0) &&
+          ((MagickRealType) q->opacity > threshold.opacity))
+        q->opacity=(Quantum) QuantumRange;
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          ((MagickRealType) indexes[x] > threshold.index))
+        indexes[x]=(Quantum) QuantumRange;
+      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_WhiteThresholdImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/magick/threshold.h b/magick/threshold.h
new file mode 100644
index 0000000..76baa6b
--- /dev/null
+++ b/magick/threshold.h
@@ -0,0 +1,59 @@
+/*
+  Copyright 1999-2009 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 unsigned long,const unsigned long,
+    const long,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 *),
+  ListThresholdMaps(FILE *,ExceptionInfo *),
+  OrderedDitherImage(Image *),  /* deprecated */
+  OrderedDitherImageChannel(Image *,const ChannelType,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/magick/timer.c b/magick/timer.c
new file mode 100644
index 0000000..06e3b3d
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/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(__WINDOWS__)
+  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(__WINDOWS__)
+  return(NTUserTime());
+#else
+  return((double) clock()/CLK_TCK);
+#endif
+#endif
+}
diff --git a/magick/timer.h b/magick/timer.h
new file mode 100644
index 0000000..e108f24
--- /dev/null
+++ b/magick/timer.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2009 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;
+  
+  unsigned long
+    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/magick/token-private.h b/magick/token-private.h
new file mode 100644
index 0000000..e6e623d
--- /dev/null
+++ b/magick/token-private.h
@@ -0,0 +1,151 @@
+/*
+  Copyright 1999-2009 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
+{
+  unsigned long
+    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 long GetNextUTFCode(const char *text,size_t *octets)
+{
+  register long
+    i;
+
+  register unsigned long
+    c,
+    unicode;
+
+  unsigned long
+    code;
+
+  *octets=0;
+  if (text == (const char *) NULL)
+    {
+      errno=EINVAL;
+      return(0);
+    }
+  code=(unsigned long) (*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(0);
+          }
+        *octets=(size_t) (i+1);
+        return(unicode);
+      }
+    c=(unsigned long) (*text++ ^ 0x80) & 0xff;
+    if ((c & 0xc0) != 0)
+      {
+        errno=EILSEQ;
+        return(0);
+      }
+    unicode=(unicode << 6) | c;
+  }
+  errno=EILSEQ;
+  return(0);
+}
+
+static unsigned long GetUTFCode(const char *text)
+{
+  size_t
+    octets;
+
+  return(GetNextUTFCode(text,&octets));
+}
+
+static size_t GetUTFOctets(const char *text)
+{
+  size_t
+    octets;
+
+  (void) GetNextUTFCode(text,&octets);
+  return(octets);
+}
+
+static inline MagickBooleanType IsUTFSpace(unsigned long 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(unsigned long code)
+{
+  unsigned long
+    mask;
+
+  mask=(unsigned long) 0x7fffffff;
+  if (((code & ~mask) != 0) && ((code < 0xd800) || (code > 0xdfff)) &&
+      (code != 0xfffe) && (code != 0xffff))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static inline MagickBooleanType IsUTFAscii(unsigned long code)
+{
+  unsigned long
+    mask;
+
+  mask=(unsigned long) 0x7f;
+  if ((code & ~mask) != 0)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/token.c b/magick/token.c
new file mode 100644
index 0000000..26d918f
--- /dev/null
+++ b/magick/token.c
@@ -0,0 +1,962 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    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-2009 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 "magick/studio.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/token-private.h"
+#include "magick/utility.h"
+
+/*
+  Typedef declaractions.
+*/
+struct _TokenInfo
+{
+  int
+    state;
+
+  MagickStatusType
+    flag;
+
+  long
+    offset;
+
+  char
+    quote;
+
+  unsigned long
+    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)).
+%
+%  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 long
+    i;
+
+  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=strtod(p,&q);
+        if ((p != q) && (*p != ','))
+          {
+            for ( ; (p < q) && (*p != ','); p++)
+              token[i++]=(*p);
+            if (*p == '%')
+              token[i++]=(*p++);
+            break;
+          }
+        if ((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-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=(long) 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,MagickTrue,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 '\\':
+      {
+        pattern+=GetUTFOctets(pattern);
+        if (GetUTFCode(pattern) != 0)
+          pattern+=GetUTFOctets(pattern);
+        break;
+      }
+      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 '[':
+      {
+        unsigned long
+          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;
+      }
+      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 long sindex(int c,const char *string)
+{
+  register const char
+    *p;
+
+  for (p=string; *p != '\0'; p++)
+    if (c == (int) (*p))
+      return(p-string);
+  return(-1);
+}
+
+static void StoreToken(TokenInfo *token_info,char *string,
+  size_t max_token_length,int c)
+{
+  register long
+    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 long
+    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/magick/token.h b/magick/token.h
new file mode 100644
index 0000000..69993e6
--- /dev/null
+++ b/magick/token.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2009 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/magick/transform.c b/magick/transform.c
new file mode 100644
index 0000000..d956cc0
--- /dev/null
+++ b/magick/transform.c
@@ -0,0 +1,2132 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%       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-2009 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 "magick/studio.h"
+#include "magick/cache.h"
+#include "magick/cache-view.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/colorspace-private.h"
+#include "magick/composite.h"
+#include "magick/effect.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/image.h"
+#include "magick/memory_.h"
+#include "magick/layer.h"
+#include "magick/list.h"
+#include "magick/monitor.h"
+#include "magick/monitor-private.h"
+#include "magick/pixel-private.h"
+#include "magick/resource_.h"
+#include "magick/resize.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/transform.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C h o p I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Chop() 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"
+
+  Image
+    *chop_image;
+
+  long
+    j,
+    y;
+
+  MagickBooleanType
+    proceed;
+
+  RectangleInfo
+    extent;
+
+  register long
+    i;
+
+  CacheView
+    *chop_view,
+    *image_view;
+
+  /*
+    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+(long) chop_info->width) < 0) ||
+      ((chop_info->y+(long) chop_info->height) < 0) ||
+      (chop_info->x > (long) image->columns) ||
+      (chop_info->y > (long) image->rows))
+    ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
+  extent=(*chop_info);
+  if ((extent.x+(long) extent.width) > (long) image->columns)
+    extent.width=(unsigned long) ((long) image->columns-extent.x);
+  if ((extent.y+(long) extent.height) > (long) image->rows)
+    extent.height=(unsigned long) ((long) image->rows-extent.y);
+  if (extent.x < 0)
+    {
+      extent.width-=(unsigned long) (-extent.x);
+      extent.x=0;
+    }
+  if (extent.y < 0)
+    {
+      extent.height-=(unsigned long) (-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.
+  */
+  i=0;
+  j=0;
+  image_view=AcquireCacheView(image);
+  chop_view=AcquireCacheView(chop_image);
+  for (y=0; y < (long) extent.y; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict chop_indexes,
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
+        {
+          *q=(*p);
+          if (indexes != (IndexPacket *) NULL)
+            {
+              if (chop_indexes != (IndexPacket *) NULL)
+                *chop_indexes++=indexes[x];
+            }
+          q++;
+        }
+      p++;
+    }
+    if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  /*
+    Extract chop image.
+  */
+  i+=extent.height;
+  for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict chop_indexes,
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
+      exception);
+    if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      break;
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
+    for (x=0; x < (long) image->columns; x++)
+    {
+      if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
+        {
+          *q=(*p);
+          if (indexes != (IndexPacket *) NULL)
+            {
+              if (chop_indexes != (IndexPacket *) NULL)
+                *chop_indexes++=indexes[x];
+            }
+          q++;
+        }
+      p++;
+    }
+    if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  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)
+{
+  Image
+    *cmyk_image,
+    *cmyk_images;
+
+  long
+    y;
+
+  register long
+    i;
+
+  /*
+    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 < (long) 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);
+    for (y=0; y < (long) images->rows; y++)
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      p=GetVirtualPixels(images,0,y,images->columns,1,exception);
+      q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
+      if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+        break;
+      for (x=0; x < (long) images->columns; x++)
+      {
+        q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
+        p++;
+        q++;
+      }
+      if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
+        break;
+    }
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    for (y=0; y < (long) images->rows; y++)
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      p=GetVirtualPixels(images,0,y,images->columns,1,exception);
+      q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
+      if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+        break;
+      for (x=0; x < (long) images->columns; x++)
+      {
+        q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
+        p++;
+        q++;
+      }
+      if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
+        break;
+    }
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    for (y=0; y < (long) images->rows; y++)
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      p=GetVirtualPixels(images,0,y,images->columns,1,exception);
+      q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
+      if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+        break;
+      for (x=0; x < (long) images->columns; x++)
+      {
+        q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
+        p++;
+        q++;
+      }
+      if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
+        break;
+    }
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    for (y=0; y < (long) images->rows; y++)
+    {
+      register const PixelPacket
+        *__restrict p;
+
+      register IndexPacket
+        *__restrict indexes;
+
+      register long
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      p=GetVirtualPixels(images,0,y,images->columns,1,exception);
+      q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
+      if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+        break;
+      indexes=GetAuthenticIndexQueue(cmyk_image);
+      for (x=0; x < (long) images->columns; x++)
+      {
+        indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
+        p++;
+      }
+      if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
+        break;
+    }
+    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.
+%
+%  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"
+
+  Image
+    *crop_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    bounding_box,
+    page;
+
+  CacheView
+    *crop_view,
+    *image_view;
+
+  /*
+    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) >= (long) page.width) ||
+      ((bounding_box.y-page.y) >= (long) page.height) ||
+      ((page.x-bounding_box.x) > (long) image->columns) ||
+      ((page.y-bounding_box.y) > (long) 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.opacity=(Quantum) TransparentOpacity;
+      (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 ((unsigned long) (page.x+page.width) > image->columns)
+    page.width=image->columns-page.x;
+  if (geometry->width != 0)
+    if (page.width > geometry->width)
+      page.width=geometry->width;
+  if ((unsigned long) (page.y+page.height) > image->rows)
+    page.height=image->rows-page.y;
+  if (geometry->height != 0)
+    if (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 (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
+      ((long) (bounding_box.y+bounding_box.height) > (long) 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)
+#endif
+  for (y=0; y < (long) crop_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict crop_indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    if (indexes != (IndexPacket *) NULL)
+      {
+        crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
+        if (crop_indexes != (IndexPacket *) NULL)
+          (void) CopyMagickMemory(crop_indexes,indexes,(size_t)
+            crop_image->columns*sizeof(*crop_indexes));
+      }
+    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);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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"
+
+  Image
+    *excerpt_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *excerpt_view,
+    *image_view;
+
+  /*
+    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 < (long) excerpt_image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict excerpt_indexes,
+      *__restrict indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (indexes != (IndexPacket *) NULL)
+      {
+        excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
+        if (excerpt_indexes != (IndexPacket *) NULL)
+          (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
+            excerpt_image->columns*sizeof(*excerpt_indexes));
+      }
+    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.opacity != OpaqueOpacity)
+    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"
+
+  Image
+    *flip_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *flip_view,
+    *image_view;
+
+  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;
+  image_view=AcquireCacheView(image);
+  flip_view=AcquireCacheView(flip_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) flip_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict flip_indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
+      flip_image->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    if (indexes != (const IndexPacket *) NULL)
+      {
+        flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
+        if (flip_indexes != (IndexPacket *) NULL)
+          (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
+            sizeof(*flip_indexes));
+      }
+    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 (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"
+
+  Image
+    *flop_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *flop_view,
+    *image_view;
+
+  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;
+  image_view=AcquireCacheView(image);
+  flop_view=AcquireCacheView(flop_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (long) flop_image->rows; y++)
+  {
+    register const IndexPacket
+      *__restrict indexes;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict flop_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    q+=flop_image->columns;
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
+    for (x=0; x < (long) flop_image->columns; x++)
+    {
+      (*--q)=(*p++);
+      if ((indexes != (const IndexPacket *) NULL) &&
+          (flop_indexes != (IndexPacket *) NULL))
+        flop_indexes[flop_image->columns-x-1]=indexes[x];
+    }
+    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 (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 long x_offset,
+%        const long 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 unsigned long columns,const unsigned long rows,
+  const long sx,const long sy,const long dx,const long dy,
+  ExceptionInfo *exception)
+{
+  long
+    y;
+
+  MagickBooleanType
+    status;
+
+  CacheView
+    *source_view,
+    *destination_view;
+
+  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 < (long) rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes,
+      *__restrict destination_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    /*
+      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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(source_view);
+    for (x=0; x < (long) columns; x++)
+      *q++=(*p++);
+    if (indexes != (IndexPacket *) NULL)
+      {
+        destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
+        for (x=0; x < (long) columns; x++)
+          destination_indexes[x]=indexes[x];
+      }
+    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 long x_offset,
+  const long 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+=image->columns;
+  while (offset.x >= (long) image->columns)
+    offset.x-=image->columns;
+  while (offset.y < 0)
+    offset.y+=image->rows;
+  while (offset.y >= (long) image->rows)
+    offset.y-=image->rows;
+  /*
+    Roll image.
+  */
+  status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
+    (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
+    offset.y,0,0,exception);
+  (void) SetImageProgress(image,RollImageTag,0,3);
+  status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
+    (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
+    exception);
+  (void) SetImageProgress(image,RollImageTag,1,3);
+  status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
+    offset.y,(long) 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=(long) shave_info->width+image->page.x;
+  geometry.y=(long) 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-=shave_info->width;
+  shave_image->page.y-=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"
+
+  Image
+    *splice_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  RectangleInfo
+    splice_geometry;
+
+  register long
+    i;
+
+  CacheView
+    *image_view,
+    *splice_view;
+
+  /*
+    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+=splice_geometry.width/2;
+      break;
+    }
+    case NorthEastGravity:
+    {
+      splice_geometry.x+=splice_geometry.width;
+      break;
+    }
+    case WestGravity:
+    {
+      splice_geometry.y+=splice_geometry.width/2;
+      break;
+    }
+    case StaticGravity:
+    case CenterGravity:
+    {
+      splice_geometry.x+=splice_geometry.width/2;
+      splice_geometry.y+=splice_geometry.height/2;
+      break;
+    }
+    case EastGravity:
+    {
+      splice_geometry.x+=splice_geometry.width;
+      splice_geometry.y+=splice_geometry.height/2;
+      break;
+    }
+    case SouthWestGravity:
+    {
+      splice_geometry.y+=splice_geometry.height;
+      break;
+    }
+    case SouthGravity:
+    {
+      splice_geometry.x+=splice_geometry.width/2;
+      splice_geometry.y+=splice_geometry.height;
+      break;
+    }
+    case SouthEastGravity:
+    {
+      splice_geometry.x+=splice_geometry.width;
+      splice_geometry.y+=splice_geometry.height;
+      break;
+    }
+  }
+  /*
+    Splice image.
+  */
+  status=MagickTrue;
+  i=0;
+  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 < (long) splice_geometry.y; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes,
+      *__restrict splice_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__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 PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
+    for (x=0; x < splice_geometry.x; x++)
+    {
+      q->red=p->red;
+      q->green=p->green;
+      q->blue=p->blue;
+      q->opacity=OpaqueOpacity;
+      if (image->matte != MagickFalse)
+        q->opacity=p->opacity;
+      if (image->colorspace == CMYKColorspace)
+        splice_indexes[x]=(*indexes++);
+      p++;
+      q++;
+    }
+    for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
+      q++;
+    for ( ; x < (long) splice_image->columns; x++)
+    {
+      q->red=p->red;
+      q->green=p->green;
+      q->blue=p->blue;
+      q->opacity=OpaqueOpacity;
+      if (image->matte != MagickFalse)
+        q->opacity=p->opacity;
+      if (image->colorspace == CMYKColorspace)
+        splice_indexes[x]=(*indexes++);
+      p++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
+      status=MagickFalse;
+    proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
+    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=(long) (splice_geometry.y+splice_geometry.height);
+       y < (long) splice_image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict indexes,
+      *__restrict splice_indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
+      image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
+      exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
+    for (x=0; x < splice_geometry.x; x++)
+    {
+      q->red=p->red;
+      q->green=p->green;
+      q->blue=p->blue;
+      q->opacity=OpaqueOpacity;
+      if (image->matte != MagickFalse)
+        q->opacity=p->opacity;
+      if (image->colorspace == CMYKColorspace)
+        splice_indexes[x]=(*indexes++);
+      p++;
+      q++;
+    }
+    for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
+      q++;
+    for ( ; x < (long) splice_image->columns; x++)
+    {
+      q->red=p->red;
+      q->green=p->green;
+      q->blue=p->blue;
+      q->opacity=OpaqueOpacity;
+      if (image->matte != MagickFalse)
+        q->opacity=p->opacity;
+      if (image->colorspace == CMYKColorspace)
+        splice_indexes[x]=(*indexes++);
+      p++;
+      q++;
+    }
+    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 returned.
+%
+%  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.
+%
+*/
+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;
+
+      RectangleInfo
+        geometry;
+
+      /*
+        Crop image to a user specified size.
+      */
+      crop_image=NewImageList();
+      flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
+        &(*image)->exception);
+      if (((geometry.width == 0) && (geometry.height == 0)) ||
+          ((flags & XValue) != 0) || ((flags & YValue) != 0))
+        {
+          crop_image=CropImage(transform_image,&geometry,&(*image)->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;
+            }
+        }
+      else
+        if ((transform_image->columns > geometry.width) ||
+            (transform_image->rows > geometry.height))
+          {
+            Image
+              *next;
+
+            long
+              y;
+
+            register long
+              x;
+
+            unsigned long
+              height,
+              width;
+
+            /*
+              Crop repeatedly to create uniform scenes.
+            */
+            if (transform_image->page.width == 0)
+              transform_image->page.width=transform_image->columns;
+            if (transform_image->page.height == 0)
+              transform_image->page.height=transform_image->rows;
+            width=geometry.width;
+            if (width == 0)
+              width=transform_image->page.width;
+            height=geometry.height;
+            if (height == 0)
+              height=transform_image->page.height;
+            next=NewImageList();
+            for (y=0; y < (long) transform_image->page.height; y+=height)
+            {
+              for (x=0; x < (long) transform_image->page.width; x+=width)
+              {
+                geometry.width=width;
+                geometry.height=height;
+                geometry.x=x;
+                geometry.y=y;
+                next=CropImage(transform_image,&geometry,&(*image)->exception);
+                if (next == (Image *) NULL)
+                  break;
+                AppendImageToList(&crop_image,next);
+              }
+              if (next == (Image *) NULL)
+                break;
+            }
+          }
+      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);
+  if ((transform_image->columns == geometry.width) &&
+      (transform_image->rows == geometry.height))
+    return(MagickTrue);
+  resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
+    &(*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 long
+    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"
+
+  Image
+    *transpose_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    page;
+
+  CacheView
+    *image_view,
+    *transpose_view;
+
+  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 < (long) image->rows; y++)
+  {
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict transpose_indexes,
+      *__restrict indexes;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
+      image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
+      1,transpose_image->rows,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (indexes != (IndexPacket *) NULL)
+      {
+        transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
+        if (transpose_indexes != (IndexPacket *) NULL)
+          (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
+            image->columns*sizeof(*transpose_indexes));
+      }
+    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);
+  if (page.width != 0)
+    page.x=(long) (page.width-transpose_image->columns-page.x);
+  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"
+
+  Image
+    *transverse_image;
+
+  long
+    progress,
+    y;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    page;
+
+  CacheView
+    *image_view,
+    *transverse_view;
+
+  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 < (long) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const PixelPacket
+      *__restrict p;
+
+    register IndexPacket
+      *__restrict transverse_indexes,
+      *__restrict indexes;
+
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
+      1),0,1,transverse_image->rows,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    q+=image->columns;
+    for (x=0; x < (long) image->columns; x++)
+      *--q=(*p++);
+    indexes=GetCacheViewAuthenticIndexQueue(image_view);
+    if (indexes != (IndexPacket *) NULL)
+      {
+        transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
+        if (transverse_indexes != (IndexPacket *) NULL)
+          for (x=0; x < (long) image->columns; x++)
+            transverse_indexes[image->columns-x-1]=indexes[x];
+      }
+    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.height != 0)
+    page.y=(long) (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.opacity=(Quantum) TransparentOpacity;
+      (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/magick/transform.h b/magick/transform.h
new file mode 100644
index 0000000..6561f9e
--- /dev/null
+++ b/magick/transform.h
@@ -0,0 +1,48 @@
+/*
+  Copyright 1999-2009 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 *),
+  *ExcerptImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *ExtentImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *FlipImage(const Image *,ExceptionInfo *),
+  *FlopImage(const Image *,ExceptionInfo *),
+  *RollImage(const Image *,const long,const long,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/magick/type.c b/magick/type.c
new file mode 100644
index 0000000..fa7eaf4
--- /dev/null
+++ b/magick/type.c
@@ -0,0 +1,1351 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                        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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/client.h"
+#include "magick/configure.h"
+#include "magick/draw.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/semaphore.h"
+#include "magick/splay-tree.h"
+#include "magick/string_.h"
+#include "magick/type.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/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(__WINDOWS__)
+# include "magick/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 *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y T y p e L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyTypeList() deallocates memory associated with the font list.
+%
+%  The format of the DestroyTypeList method is:
+%
+%      void DestroyTypeList(void)
+%
+*/
+MagickExport void DestroyTypeList(void)
+{
+  AcquireSemaphoreInfo(&type_semaphore);
+  if (type_list != (SplayTreeInfo *) NULL)
+    type_list=DestroySplayTree(type_list);
+  instantiate_type=MagickFalse;
+  RelinquishSemaphoreInfo(type_semaphore);
+  DestroySemaphoreInfo(&type_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   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 unsigned long 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 unsigned long MagickMax(const unsigned long x,
+  const unsigned long y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline unsigned long MagickMin(const unsigned long x,
+  const unsigned long y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
+  const StyleType style,const StretchType stretch,const unsigned long weight,
+  ExceptionInfo *exception)
+{
+  typedef struct _Fontmap
+  {
+    const char
+      *name,
+      *substitute;
+  } Fontmap;
+
+  const TypeInfo
+    *type_info;
+
+  long
+    range;
+
+  register const TypeInfo
+    *p;
+
+  register long
+    i;
+
+  static Fontmap
+    fontmap[] =
+    {
+      { "fixed", "courier" },
+      { "modern","courier" },
+      { "monotype corsiva", "courier" },
+      { "news gothic", "helvetica" },
+      { "system", "courier" },
+      { "terminal", "courier" },
+      { "wingdings", "symbol" },
+      { NULL, NULL }
+    };
+
+  unsigned long
+    max_score,
+    score;
+
+  /*
+    Check for an exact type match.
+  */
+  (void) GetTypeInfo("*",exception);
+  if (type_list == (SplayTreeInfo *) NULL)
+    return((TypeInfo *) NULL);
+  AcquireSemaphoreInfo(&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;
+  }
+  RelinquishSemaphoreInfo(type_semaphore);
+  if (type_info != (const TypeInfo *) NULL)
+    return(type_info);
+  /*
+    Check for types in the same family.
+  */
+  max_score=0;
+  AcquireSemaphoreInfo(&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-((long) MagickMax(MagickMin(weight,900),p->weight)-
+        (long) MagickMin(MagickMin(weight,900),p->weight))))/800;
+    if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
+      score+=8;
+    else
+      {
+        range=(long) UltraExpandedStretch-(long) NormalStretch;
+        score+=(8*(range-((long) MagickMax(stretch,p->stretch)-
+          (long) MagickMin(stretch,p->stretch))))/range;
+      }
+    if (score > max_score)
+      {
+        max_score=score;
+        type_info=p;
+      }
+    p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  }
+  RelinquishSemaphoreInfo(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,
+%        unsigned long *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,
+  unsigned long *number_fonts,ExceptionInfo *exception)
+{
+  const TypeInfo
+    **fonts;
+
+  register const TypeInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate type list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_fonts != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(type_semaphore);
+  qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
+  fonts[i]=(TypeInfo *) NULL;
+  *number_fonts=(unsigned long) 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,unsigned long *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,unsigned long *number_fonts,
+  ExceptionInfo *exception)
+{
+  char
+    **fonts;
+
+  register const TypeInfo
+    *p;
+
+  register long
+    i;
+
+  /*
+    Allocate type list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_fonts != (unsigned long *) 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.
+  */
+  AcquireSemaphoreInfo(&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);
+  }
+  RelinquishSemaphoreInfo(type_semaphore);
+  qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
+  fonts[i]=(char *) NULL;
+  *number_fonts=(unsigned long) 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 long
+    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 < (long) 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))
+    {
+      AcquireSemaphoreInfo(&type_semaphore);
+      if ((type_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_type == MagickFalse))
+        {
+          (void) LoadTypeLists(MagickTypeFilename,exception);
+#if defined(__WINDOWS__)
+          (void) NTLoadTypeLists(type_list,exception);
+#endif
+#if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
+          (void) LoadFontConfigFonts(type_list,exception);
+#endif
+          instantiate_type=MagickTrue;
+        }
+      RelinquishSemaphoreInfo(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 long
+    i;
+
+  unsigned long
+    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 < (long) 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) fprintf(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=MagickOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
+    stretch=MagickOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
+    glyphs="unknown";
+    if (type_info[i]->glyphs != (char *) NULL)
+      glyphs=type_info[i]->glyphs;
+    (void) FormatMagickString(weight,MaxTextExtent,"%lu",type_info[i]->weight);
+    (void) fprintf(file,"  Font: %s\n",name);
+    (void) fprintf(file,"    family: %s\n",family);
+    (void) fprintf(file,"    style: %s\n",style);
+    (void) fprintf(file,"    stretch: %s\n",stretch);
+    (void) fprintf(file,"    weight: %s\n",weight);
+    (void) fprintf(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 unsigned long 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 unsigned long 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(__WINDOWS__)
+  /*
+    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=(unsigned long) atol(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(__WINDOWS__)
+            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->glyphs=path;
+            break;
+          }
+        break;
+      }
+      case 'M':
+      case 'm':
+      {
+        if (LocaleCompare((char *) keyword,"metrics") == 0)
+          {
+            char
+              *path;
+
+            path=ConstantString(token);
+#if defined(__WINDOWS__)
+            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) ParseMagickOption(
+              MagickStretchOptions,MagickFalse,token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"style") == 0)
+          {
+            type_info->style=(StyleType) ParseMagickOption(MagickStyleOptions,
+              MagickFalse,token);
+            break;
+          }
+        break;
+      }
+      case 'W':
+      case 'w':
+      {
+        if (LocaleCompare((char *) keyword,"weight") == 0)
+          {
+            type_info->weight=(unsigned long) atol(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) FormatMagickString(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
+}
diff --git a/magick/type.h b/magick/type.h
new file mode 100644
index 0000000..d4d1db5
--- /dev/null
+++ b/magick/type.h
@@ -0,0 +1,106 @@
+/*
+  Copyright 1999-2009 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
+{
+  unsigned long
+    face;
+
+  char
+    *path,
+    *name,
+    *description,
+    *family;
+
+  StyleType
+    style;
+
+  StretchType
+    stretch;
+
+  unsigned long
+    weight;
+
+  char
+    *encoding,
+    *foundry,
+    *format,
+    *metrics,
+    *glyphs;
+
+  MagickBooleanType
+    stealth;
+
+  struct _TypeInfo
+    *previous,
+    *next;  /* deprecated, use GetTypeInfoList() */
+
+  unsigned long
+    signature;
+} TypeInfo;
+
+extern MagickExport char
+  **GetTypeList(const char *,unsigned long *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListTypeInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport const TypeInfo
+  *GetTypeInfo(const char *,ExceptionInfo *),
+  *GetTypeInfoByFamily(const char *,const StyleType,const StretchType,
+    const unsigned long,ExceptionInfo *),
+  **GetTypeInfoList(const char *,unsigned long *,ExceptionInfo *);
+
+MagickExport void
+  DestroyTypeList(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/utility.c b/magick/utility.c
new file mode 100644
index 0000000..c78affa
--- /dev/null
+++ b/magick/utility.c
@@ -0,0 +1,1888 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%             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-2009 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 "magick/studio.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/color.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/list.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/option.h"
+#include "magick/resource_.h"
+#include "magick/semaphore.h"
+#include "magick/signature-private.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#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
+    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) FormatMagickString(message,MaxTextExtent,"%s:%s",format,filename);
+      (void) CopyMagickString(filename,message,MaxTextExtent);
+      return;
+    }
+  GetPathComponent(filename,RootPath,root);
+  (void) FormatMagickString(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)
+    {
+      long
+        j;
+
+      unsigned char
+        code[3];
+
+      code[0]='\0';
+      code[1]='\0';
+      code[2]='\0';
+      for (j=0; j < (long) 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,unsigned long 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 unsigned long components)
+{
+  register long
+    i;
+
+  for (i=0; i < (long) 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
+    *cwd,
+    home_directory[MaxTextExtent],
+    **vector;
+
+  long
+    count,
+    parameters;
+
+  register long
+    i,
+    j;
+
+  unsigned long
+    number_files;
+
+  /*
+    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';
+  cwd=getcwd(home_directory,MaxTextExtent);
+  count=0;
+  for (i=0; i < (long) *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=ParseMagickOption(MagickCommandOptions,MagickFalse,option);
+    if (parameters > 0)
+      {
+        /*
+          Do not expand command option parameters.
+        */
+        for (j=0; j < parameters; j++)
+        {
+          i++;
+          if (i == (long) *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);
+        filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
+          &number_files);
+      }
+    else
+      {
+        char
+          *files;
+
+        ExceptionInfo
+          *exception;
+
+        int
+          number_images;
+
+        /*
+          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;
+        StripString(files);
+        filelist=StringToArgv(files,&number_images);
+        files=DestroyString(files);
+        number_files=(unsigned long) number_images;
+        if (filelist != (char **) NULL)
+          {
+            number_files--;
+            for (j=0; j < (long) number_files; j++)
+              filelist[j]=filelist[j+1];
+          }
+      }
+    if (filelist == (char **) NULL)
+      continue;
+    for (j=0; j < (long) number_files; j++)
+      if (IsPathDirectory(filelist[j]) <= 0)
+        break;
+    if (j == (long) number_files)
+      {
+        for (j=0; j < (long) 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 < (long) number_files; j++)
+    {
+      (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)
+        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)
+            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
+    *cwd;
+
+  *path='\0';
+  cwd=getcwd(path,(unsigned long) extent);
+#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK)
+  {
+    char
+      link_path[MaxTextExtent],
+      real_path[PATH_MAX+1];
+
+    ssize_t
+      count;
+
+    (void) FormatMagickString(link_path,MaxTextExtent,"/proc/%ld/exe",
+      (long) getpid());
+    count=readlink(link_path,real_path,PATH_MAX);
+    if (count == -1)
+      {
+        (void) FormatMagickString(link_path,MaxTextExtent,"/proc/%ld/file",
+          (long) getpid());
+        count=readlink(link_path,real_path,PATH_MAX);
+      }
+    if ((count > 0) && (count <= (ssize_t) PATH_MAX))
+      {
+        real_path[count]='\0';
+        (void) CopyMagickString(path,real_path,extent);
+      }
+  }
+#endif
+#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
+  {
+    char
+      executable_path[PATH_MAX << 1],
+      real_path[PATH_MAX+1];
+
+    uint32_t
+      length;
+
+    length=sizeof(executable_path);
+    if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
+        (realpath(executable_path,real_path) != (char *) NULL))
+      (void) CopyMagickString(path,real_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(__WINDOWS__)
+  NTGetExecutionPath(path,extent);
+#endif
+  return(IsPathAccessible(path));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 long
+        i;
+
+      /*
+        Not UTF-8, just copy.
+      */
+      length=strlen(source);
+      utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
+      if (utf16 == (wchar_t *) NULL)
+        return((wchar_t *) NULL);
+      for (i=0; i <= (long) 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(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 == ':') && (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,
+%        unsigned long *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,
+  unsigned long *number_components)
+{
+  char
+    **components;
+
+  register const char
+    *p,
+    *q;
+
+  register long
+    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 < (long) *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,
+%        long *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,
+  unsigned long *number_entries)
+{
+  char
+    **filelist;
+
+  DIR
+    *current_directory;
+
+  struct dirent
+    *buffer,
+    *entry;
+
+  unsigned long
+    max_entries;
+
+  /*
+    Open directory.
+  */
+  assert(directory != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
+  assert(pattern != (const char *) NULL);
+  assert(number_entries != (unsigned long *) 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(__WINDOWS__)
+        (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);
+        if (IsPathDirectory(entry->d_name) > 0)
+          (void) ConcatenateMagickString(filelist[*number_entries],
+            DirectorySeparator,MaxTextExtent);
+        (*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 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:
+%
+%      unsigned long MultilineCensus(const char *label)
+%
+%  A description of each parameter follows.
+%
+%   o  label:  This character string is the label.
+%
+%
+*/
+MagickExport unsigned long MultilineCensus(const char *label)
+{
+  unsigned long
+    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(path);
+    if (unicode_path == (wchar_t *) NULL)
+      return((FILE *) NULL);
+    unicode_mode=ConvertUTF8ToUTF16(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 verbose,const char *command)
+%
+%  A description of each parameter follows:
+%
+%    o verbose: A value other than 0 prints the executed command before it is
+%      invoked.
+%
+%    o command: This string is the command to execute.
+%
+*/
+MagickExport int SystemCommand(const MagickBooleanType verbose,
+  const char *command)
+{
+  int
+    status;
+
+  if (verbose != MagickFalse)
+    {
+      (void) fprintf(stderr,"%s\n",command);
+      (void) fflush(stderr);
+    }
+  status=(-1);
+#if defined(MAGICKCORE_POSIX_SUPPORT)
+#if !defined(MAGICKCORE_HAVE_EXECVP)
+  status=system(command);
+#else
+  if (strspn(command,"&;<>|") == 0)
+    status=system(command);
+  else
+    {
+      char
+        **arguments;
+
+      int
+        number_arguments;
+
+      arguments=StringToArgv(command,&number_arguments);
+      if (arguments == (char **) NULL)
+        status=system(command);
+      else
+        {
+          pid_t
+            child_pid;
+
+          register long
+            i;
+
+          /*
+            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);
+                  }
+              }
+          for (i=0; i < number_arguments; i++)
+            arguments[i]=DestroyString(arguments[i]);
+          arguments=(char **) RelinquishMagickMemory(arguments);
+        }
+    }
+#endif
+#elif defined(__WINDOWS__)
+  status=NTSystemCommand(command);
+#elif defined(macintosh)
+  status=MACSystemCommand(command);
+#elif defined(vms)
+  status=system(command);
+#else
+#  error No suitable system() method.
+#endif
+  if (status < 0)
+    {
+      char
+        *message;
+
+      ExceptionInfo
+        *exception;
+
+      exception=AcquireExceptionInfo();
+      message=GetExceptionMessage(errno);
+      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
+        "`%s': %s",command,message);
+      message=DestroyString(message);
+      CatchException(exception);
+      exception=DestroyExceptionInfo(exception);
+    }
+  return(status);
+}
diff --git a/magick/utility.h b/magick/utility.h
new file mode 100644
index 0000000..3830740
--- /dev/null
+++ b/magick/utility.h
@@ -0,0 +1,74 @@
+/*
+  Copyright 1999-2009 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 *,unsigned long *),
+  **ListFiles(const char *,const char *,unsigned long *);
+
+extern MagickExport FILE
+  *OpenMagickStream(const char *,const char *);
+
+extern MagickExport int
+  SystemCommand(const MagickBooleanType,const char *);
+
+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 unsigned char
+  *Base64Decode(const char *, size_t *);
+
+extern MagickExport unsigned long
+  MultilineCensus(const char *);
+
+extern MagickExport void
+  AppendImageFormat(const char *,char *),
+  ChopPathComponents(char *,const unsigned long),
+  ExpandFilename(char *),
+  GetPathComponent(const char *,PathType,char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/version.c b/magick/version.c
new file mode 100644
index 0000000..7dbeb31
--- /dev/null
+++ b/magick/version.c
@@ -0,0 +1,262 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               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-2009 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 "magick/studio.h"
+#include "magick/configure.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/hashmap.h"
+#include "magick/option.h"
+#include "magick/string_.h"
+#include "magick/utility.h"
+#include "magick/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 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) FormatMagickString(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(unsigned long *depth)
+%
+%  A description of each parameter follows:
+%
+%    o depth: the quantum depth is returned as a number.
+%
+*/
+MagickExport const char *GetMagickQuantumDepth(unsigned long *depth)
+{
+  if (depth != (unsigned long *) NULL)
+    *depth=(unsigned long) 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(unsigned long *range)
+%
+%  A description of each parameter follows:
+%
+%    o range: the quantum range is returned as a number.
+%
+*/
+MagickExport const char *GetMagickQuantumRange(unsigned long *range)
+{
+  if (range != (unsigned long *) NULL)
+    *range=(unsigned long) 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(unsigned long *version)
+%
+%  A description of each parameter follows:
+%
+%    o version: the ImageMagick version is returned as a number.
+%
+*/
+MagickExport const char *GetMagickVersion(unsigned long *version)
+{
+  if (version != (unsigned long *) NULL)
+    *version=MagickLibVersion;
+  return(MagickVersion);
+}
diff --git a/magick/version.h b/magick/version.h
new file mode 100644
index 0000000..ee69c7a
--- /dev/null
+++ b/magick/version.h
@@ -0,0 +1,84 @@
+/*
+  Copyright 1999-2009 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-2009 ImageMagick Studio LLC"
+#define MagickLibVersion  0x655
+#define MagickLibVersionText  "6.5.5"
+#define MagickLibVersionNumber  2,0,0
+#define MagickLibSubversion  "-7"
+#define MagickReleaseDate  "2009-09-01"
+#define MagickChangeDate   "20090831"
+#define MagickAuthoritativeURL  "http://www.imagemagick.org"
+#define MagickHomeURL  "file:///usr/local/share/doc/ImageMagick-6.5.5/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
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+#define MagickHDRISupport ""
+#else
+#define MagickHDRISupport "HDRI "
+#endif
+#if !defined(_OPENMP)
+#define MagickOPENMPSupport ""
+#else
+#define MagickOPENMPSupport "OpenMP "
+#endif
+#define MagickSupport MagickHDRISupport MagickOPENMPSupport
+#define MagickVersion MagickPackageName " " MagickLibVersionText \
+  MagickLibSubversion " " MagickReleaseDate " " MagickQuantumDepth " " \
+  MagickSupport MagickAuthoritativeURL
+
+extern MagickExport char
+  *GetMagickHomeURL(void);
+
+extern MagickExport const char
+  *GetMagickCopyright(void),
+  *GetMagickPackageName(void),
+  *GetMagickQuantumDepth(unsigned long *),
+  *GetMagickQuantumRange(unsigned long *),
+  *GetMagickReleaseDate(void),
+  *GetMagickVersion(unsigned long *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/version.h.in b/magick/version.h.in
new file mode 100644
index 0000000..682bb02
--- /dev/null
+++ b/magick/version.h.in
@@ -0,0 +1,84 @@
+/*
+  Copyright 1999-2009 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-2009 ImageMagick Studio LLC"
+#define MagickLibVersion  @PACKAGE_LIB_VERSION@
+#define MagickLibVersionText  "@MAGICK_LIB_VERSION_TEXT@"
+#define MagickLibVersionNumber  @MAGICK_LIB_VERSION_NUMBER@
+#define MagickLibSubversion  "@PACKAGE_LIB_SUBVERSION@"
+#define MagickReleaseDate  "@PACKAGE_RELEASE_DATE@"
+#define MagickChangeDate   "@PACKAGE_CHANGE_DATE@"
+#define MagickAuthoritativeURL  "http://www.imagemagick.org"
+#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
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+#define MagickHDRISupport ""
+#else
+#define MagickHDRISupport "HDRI "
+#endif
+#if !defined(_OPENMP)
+#define MagickOPENMPSupport ""
+#else
+#define MagickOPENMPSupport "OpenMP "
+#endif
+#define MagickSupport MagickHDRISupport MagickOPENMPSupport
+#define MagickVersion MagickPackageName " " MagickLibVersionText \
+  MagickLibSubversion " " MagickReleaseDate " " MagickQuantumDepth " " \
+  MagickSupport MagickAuthoritativeURL
+
+extern MagickExport char
+  *GetMagickHomeURL(void);
+
+extern MagickExport const char
+  *GetMagickCopyright(void),
+  *GetMagickPackageName(void),
+  *GetMagickQuantumDepth(unsigned long *),
+  *GetMagickQuantumRange(unsigned long *),
+  *GetMagickReleaseDate(void),
+  *GetMagickVersion(unsigned long *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/magick/vms.c b/magick/vms.c
new file mode 100644
index 0000000..299db90
--- /dev/null
+++ b/magick/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-2009 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 "magick/studio.h"
+#include "magick/string_.h"
+#include "magick/memory_.h"
+#include "magick/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) FormatMagickString(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 ([email protected])
+%
+%  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/magick/vms.h b/magick/vms.h
new file mode 100644
index 0000000..4611a9d
--- /dev/null
+++ b/magick/vms.h
@@ -0,0 +1,985 @@
+/*
+  Copyright 1999-2009 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/magick/widget.c b/magick/widget.c
new file mode 100644
index 0000000..d8005f1
--- /dev/null
+++ b/magick/widget.c
@@ -0,0 +1,9652 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  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-2009 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 "magick/studio.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/image.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/PreRvIcccm.h"
+#include "magick/string_.h"
+#include "magick/token.h"
+#include "magick/utility.h"
+#include "magick/xwindow-private.h"
+#include "magick/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 unsigned long 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 unsigned long 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) >= (long) 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)
+{
+  long
+    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=(long) XPixelIntensity(&window_info->pixel_info->foreground_color);
+  matte=(long) XPixelIntensity(&window_info->pixel_info->matte_color);
+  if (MagickAbsoluteValue(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;
+
+  unsigned long
+    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 < (long) 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;
+
+        unsigned long
+          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 < (long) 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 < (long) 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+=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) < (long) 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) FormatMagickString(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 < (long) 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 < (long) 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)
+          (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 < (long) 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;
+
+  unsigned long
+    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;
+
+  unsigned long
+    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;
+
+  unsigned long
+    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(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)
+          (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
+    *cwd,
+    **filelist,
+    home_directory[MaxTextExtent],
+    primary_selection[MaxTextExtent],
+    text[MaxTextExtent],
+    working_path[MaxTextExtent];
+
+  int
+    x,
+    y;
+
+  register int
+    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;
+
+  unsigned long
+    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);
+  cwd=getcwd(home_directory,MaxTextExtent);
+  (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 < (long) 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;
+
+        unsigned long
+          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 < (long) 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 < (long) files; i++)
+          if (LocaleCompare(filelist[i],reply) >= 0)
+            {
+              list_info.id=LocaleCompare(filelist[i],reply) == 0 ? i : ~0;
+              break;
+            }
+        if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_files)))
+          slider_info.id=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+=
+            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 < (int) visible_files; i++)
+            {
+              selection_info.raised=(slider_info.id+i) != list_info.id ?
+                MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < (long) 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 < (long) 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 < (long) 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 >= (long) 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 <= 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 (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;
+
+                unsigned long
+                  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 < (int) 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)
+          (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 < (long) 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;
+
+  unsigned long
+    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)
+          (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;
+
+  unsigned long
+    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)
+          (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;
+
+  unsigned long
+    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-(long)
+    ((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,
+    (unsigned long) 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,
+    (unsigned long) 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;
+
+  unsigned long
+    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;
+
+  unsigned long
+    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) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
+          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) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
+              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;
+
+  unsigned long
+    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/magick/widget.h b/magick/widget.h
new file mode 100644
index 0000000..9f97b81
--- /dev/null
+++ b/magick/widget.h
@@ -0,0 +1,58 @@
+/*
+  Copyright 1999-2009 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 "magick/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/magick/xml-tree.c b/magick/xml-tree.c
new file mode 100644
index 0000000..433ee08
--- /dev/null
+++ b/magick/xml-tree.c
@@ -0,0 +1,2625 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                             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-2009 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 "magick/studio.h"
+#include "magick/blob.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/log.h"
+#include "magick/memory_.h"
+#include "magick/semaphore.h"
+#include "magick/string_.h"
+#include "magick/xml-tree.h"
+#include "magick/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;
+
+  unsigned long
+    signature;
+};
+
+typedef struct _XMLTreeRoot
+  XMLTreeRoot;
+
+struct _XMLTreeRoot
+{
+  struct _XMLTreeInfo
+    root;
+
+  XMLTreeInfo
+    *node;
+
+  MagickBooleanType
+    standalone;
+
+  char
+    ***processing_instructions,
+    **entities,
+    ***attributes;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  unsigned long
+    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];
+
+  long
+    j;
+
+  register long
+    i;
+
+  XMLTreeInfo
+    *child,
+    *node;
+
+  unsigned long
+    number_components;
+
+  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 < (long) 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=atol(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 < (long) 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.
+%
+*/
+
+static 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);
+}
+
+MagickExport char *CanonicalXMLContent(const char *content,
+  const MagickBooleanType pedantic)
+{
+  char
+    *base64,
+    *canonical_content;
+
+  register const unsigned char
+    *p;
+
+  register long
+    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) > (long) 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+=FormatMagickString(canonical_content+i,extent,"&amp;");
+        break;
+      }
+      case '<':
+      {
+        i+=FormatMagickString(canonical_content+i,extent,"&lt;");
+        break;
+      }
+      case '>':
+      {
+        i+=FormatMagickString(canonical_content+i,extent,"&gt;");
+        break;
+      }
+      case '"':
+      {
+        i+=FormatMagickString(canonical_content+i,extent,"&quot;");
+        break;
+      }
+      case '\n':
+      {
+        if (pedantic == MagickFalse)
+          {
+            canonical_content[i++]=(char) (*p);
+            break;
+          }
+        i+=FormatMagickString(canonical_content+i,extent,"&#xA;");
+        break;
+      }
+      case '\t':
+      {
+        if (pedantic == MagickFalse)
+          {
+            canonical_content[i++]=(char) (*p);
+            break;
+          }
+        i+=FormatMagickString(canonical_content+i,extent,"&#x9;");
+        break;
+      }
+      case '\r':
+      {
+        i+=FormatMagickString(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 long
+    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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  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)
+{
+  long
+    j;
+
+  register long
+    i;
+
+  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 long
+    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];
+
+  long
+    j;
+
+  register long
+    i;
+
+  XMLTreeInfo
+    *node;
+
+  unsigned long
+    number_components;
+
+  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 < (long) number_components; i++)
+  {
+    GetPathComponent(components[i],SubimagePath,subnode);
+    GetPathComponent(components[i],CanonicalPath,tag);
+    node=GetXMLTreeChild(node,tag);
+    if (node == (XMLTreeInfo *) NULL)
+      break;
+    for (j=atol(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 < (long) 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 long
+    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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  size_t
+    extent;
+
+  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 < (long) (*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) < (long) (*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 long
+    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=(long) 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 long
+    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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  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,XMLWhitespace)) && (*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;
+
+  long
+    j,
+    l;
+
+  register char
+    *p;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  MagickBooleanType
+    status;
+
+  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 == ':') || (*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=(*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 ***) sentinel;
+  root->processing_instructions=(char ***) sentinel;
+  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)
+{
+  long
+    j;
+
+  register long
+    i;
+
+  size_t
+    length;
+
+  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;
+      length=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+=FormatMagickString(*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;
+
+  long
+    j;
+
+  register long
+    i;
+
+  size_t
+    offset;
+
+  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+=FormatMagickString(*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+=FormatMagickString(*source+(*length),*extent," %s=\"",
+      xml_info->attributes[i]);
+    (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length,
+      extent,MagickTrue);
+    *length+=FormatMagickString(*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+=FormatMagickString(*source+(*length),*extent," %s=\"",
+      attributes[i][j]);
+    (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent,
+      MagickTrue);
+    *length+=FormatMagickString(*source+(*length),*extent,"\"");
+    j+=3;
+  }
+  *length+=FormatMagickString(*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+=FormatMagickString(*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;
+
+  long
+    j,
+    k;
+
+  register char
+    *p,
+    *q;
+
+  register long
+    i;
+
+  size_t
+    extent,
+    length;
+
+  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+=FormatMagickString(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+=FormatMagickString(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/magick/xml-tree.h b/magick/xml-tree.h
new file mode 100644
index 0000000..cf5111a
--- /dev/null
+++ b/magick/xml-tree.h
@@ -0,0 +1,65 @@
+/*
+  Copyright 1999-2009 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 <magick/exception.h>
+#include <magick/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/magick/xwdfile.h_vms b/magick/xwdfile.h_vms
new file mode 100644
index 0000000..6f52d7f
--- /dev/null
+++ b/magick/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/magick/xwindow-private.h b/magick/xwindow-private.h
new file mode 100644
index 0000000..c11231e
--- /dev/null
+++ b/magick/xwindow-private.h
@@ -0,0 +1,600 @@
+/*
+  Copyright 1999-2009 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 "magick/exception.h"
+#include "magick/geometry.h"
+#include "magick/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
+{
+  unsigned long
+    colors,
+    *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;
+
+  unsigned long
+    colors;
+
+  MagickBooleanType
+    close_server,
+    backdrop;
+
+  char
+    *background_color,
+    *border_color;
+
+  char
+    *client_name;
+
+  XColormapType
+    colormap;
+
+  unsigned int
+    border_width;
+
+  unsigned long
+    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;
+
+  unsigned long
+    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;
+
+  unsigned long
+    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;
+
+  unsigned 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 *),
+  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),
+  XConfigureImageColormap(Display *,XResourceInfo *,XWindows *,Image *),
+  XConstrainWindowPosition(Display *,XWindowInfo *),
+  XDelay(Display *,const unsigned long),
+  XDestroyResourceInfo(XResourceInfo *),
+  XDestroyWindowColors(Display *,Window),
+  XDisplayImageInfo(Display *,const XResourceInfo *,XWindows *,Image *,Image *),
+  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 *),
+  XGetPixelPacket(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 unsigned long),
+  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/magick/xwindow.c b/magick/xwindow.c
new file mode 100644
index 0000000..b566217
--- /dev/null
+++ b/magick/xwindow.c
@@ -0,0 +1,9637 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%              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-2009 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 "magick/studio.h"
+#include "magick/animate.h"
+#include "magick/artifact.h"
+#include "magick/blob.h"
+#include "magick/cache.h"
+#include "magick/client.h"
+#include "magick/color.h"
+#include "magick/color-private.h"
+#include "magick/composite.h"
+#include "magick/display.h"
+#include "magick/exception.h"
+#include "magick/exception-private.h"
+#include "magick/geometry.h"
+#include "magick/identify.h"
+#include "magick/image.h"
+#include "magick/image-private.h"
+#include "magick/list.h"
+#include "magick/locale_.h"
+#include "magick/log.h"
+#include "magick/magick.h"
+#include "magick/memory_.h"
+#include "magick/monitor.h"
+#include "magick/option.h"
+#include "magick/PreRvIcccm.h"
+#include "magick/quantize.h"
+#include "magick/quantum.h"
+#include "magick/quantum-private.h"
+#include "magick/resource_.h"
+#include "magick/resize.h"
+#include "magick/shear.h"
+#include "magick/statistic.h"
+#include "magick/string_.h"
+#include "magick/transform.h"
+#include "magick/utility.h"
+#include "magick/widget.h"
+#include "magick/xwindow.h"
+#include "magick/xwindow-private.h"
+#include "magick/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) RoundToQuantum(blue_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) blue_gamma)* \
+  QuantumRange)))
+#define XGammaPixel(map,color)  (unsigned long) (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 XGreenGamma(color) RoundToQuantum(green_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) green_gamma)* \
+  QuantumRange)))
+#define XRedGamma(color) RoundToQuantum(red_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) red_gamma)* \
+  QuantumRange)))
+#define XStandardPixel(map,color)  (unsigned long) (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;
+
+  unsigned long
+    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)
+{
+  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=(unsigned long) (~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,x,y,&annotate_image->background_color,
+    &image->exception);
+  if (annotate_info->stencil == ForegroundStencil)
+    annotate_image->matte=MagickTrue;
+  exception=(&image->exception);
+  for (y=0; y < (int) annotate_image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(annotate_image,0,y,annotate_image->columns,1,
+      exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) annotate_image->columns; x++)
+    {
+      q->opacity=OpaqueOpacity;
+      if (XGetPixel(annotate_ximage,x,y) == 0)
+        {
+          /*
+            Set this pixel to the background color.
+          */
+          q->red=ScaleShortToQuantum(pixel->box_color.red);
+          q->green=ScaleShortToQuantum(pixel->box_color.green);
+          q->blue=ScaleShortToQuantum(pixel->box_color.blue);
+          if ((annotate_info->stencil == ForegroundStencil) ||
+              (annotate_info->stencil == OpaqueStencil))
+            q->opacity=(Quantum) TransparentOpacity;
+        }
+      else
+        {
+          /*
+            Set this pixel to the pen color.
+          */
+          q->red=ScaleShortToQuantum(pixel->pen_color.red);
+          q->green=ScaleShortToQuantum(pixel->pen_color.green);
+          q->blue=ScaleShortToQuantum(pixel->pen_color.blue);
+          if (annotate_info->stencil == BackgroundStencil)
+            q->opacity=(Quantum) TransparentOpacity;
+        }
+      q++;
+    }
+    if (SyncAuthenticPixels(annotate_image,exception) == MagickFalse)
+      break;
+  }
+  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) FormatMagickString(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,x,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;
+
+  MagickPixelPacket
+    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=(unsigned long) 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 unsigned long 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;
+
+  long
+    visual_mask;
+
+  register int
+    i;
+
+  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));
+  if ((resource_info->immutable != MagickFalse) && (resource_info->colors != 0))
+    if (resource_info->colors <= (1UL << (unsigned long) 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) FormatMagickString((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 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 unsigned long 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 unsigned long milliseconds)
+{
+  assert(display != (Display *) NULL);
+  (void) XFlush(display);
+  if (milliseconds == 0)
+    return;
+#if defined(__WINDOWS__)
+  Sleep(milliseconds);
+#elif defined(vms)
+  {
+    float
+      timer;
+
+    timer=milliseconds/1000.0;
+    lib$wait(&timer);
+  }
+#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(__BEOS__)
+  snooze(1000*milliseconds);
+#else
+# error "Time delay method not defined."
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
+
+  long
+    bytes;
+
+  register long
+    i;
+
+  unsigned int
+    levels;
+
+  unsigned long
+    number_pixels;
+
+  /*
+    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) fprintf(file,"Display\n  gamma: %s\n\n",
+        resource_info->display_gamma);
+  /*
+    Write info about the X image to a file.
+  */
+  (void) fprintf(file,"X\n  visual: %s\n",
+    XVisualClassName((int) windows->image.storage_class));
+  (void) fprintf(file,"  depth: %d\n",windows->image.ximage->depth);
+  if (windows->visual_info->colormap_size != 0)
+    (void) fprintf(file,"  colormap size: %d\n",
+      windows->visual_info->colormap_size);
+  if (resource_info->colormap== SharedColormap)
+    (void) fprintf(file,"  colormap type: Shared\n");
+  else
+    (void) fprintf(file,"  colormap type: Private\n");
+  (void) fprintf(file,"  geometry: %dx%d\n",windows->image.ximage->width,
+    windows->image.ximage->height);
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) fprintf(file,"  crop geometry: %s\n",windows->image.crop_geometry);
+  if (windows->image.pixmap == (Pixmap) NULL)
+    (void) fprintf(file,"  type: X Image\n");
+  else
+    (void) fprintf(file,"  type: Pixmap\n");
+  if (windows->image.shape != MagickFalse)
+    (void) fprintf(file,"  non-rectangular shape: True\n");
+  else
+    (void) fprintf(file,"  non-rectangular shape: False\n");
+  if (windows->image.shared_memory != MagickFalse)
+    (void) fprintf(file,"  shared memory: True\n");
+  else
+    (void) fprintf(file,"  shared memory: False\n");
+  (void) fprintf(file,"\n");
+  if (resource_info->font != (char *) NULL)
+    (void) fprintf(file,"Font: %s\n\n",resource_info->font);
+  if (resource_info->text_font != (char *) NULL)
+    (void) fprintf(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) fprintf(file,"Undo Edit Cache\n  levels: %u\n",levels);
+  (void) fprintf(file,"  bytes: %lumb\n",(unsigned long)
+    (bytes+(1 << 19)) >> 20);
+  (void) fprintf(file,"  limit: %lumb\n\n",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) FormatMagickString(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}
+    };
+
+  PixelPacket
+    color;
+
+  int
+    y;
+
+  long
+    value;
+
+  register char
+    *q;
+
+  register const PixelPacket
+    *p;
+
+  register int
+    i,
+    j,
+    x;
+
+  unsigned int
+    scanline_pad;
+
+  register unsigned long
+    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+=((unsigned long) 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-
+    ((unsigned long) (ximage->width*ximage->bits_per_pixel) >> 3));
+  i=0;
+  j=0;
+  q=ximage->data;
+  for (y=0; y < (int) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+    if (p == (const PixelPacket *) NULL)
+      break;
+    for (x=0; x < (int) image->columns; x++)
+    {
+      color.red=RoundToQuantum((MagickRealType) (red_map[i][j][(int)
+        ScaleQuantumToChar(p->red)] << 8));
+      color.green=RoundToQuantum((MagickRealType) (green_map[i][j][(int)
+        ScaleQuantumToChar(p->green)] << 8));
+      color.blue=RoundToQuantum((MagickRealType) (blue_map[i][j][(int)
+        ScaleQuantumToChar(p->blue)] << 8));
+      pixel=(unsigned long) (((unsigned long) color.red & 0xe0) |
+        (((unsigned long) color.green & 0xe0) >> 3) |
+        (((unsigned long) color.blue & 0xc0) >> 6));
+      *q++=(char) pixel;
+      p++;
+      j++;
+      if (j == 16)
+        j=0;
+    }
+    q+=scanline_pad;
+    i++;
+    if (i == 2)
+      i=0;
+  }
+  /*
+    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)
+{
+  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=(unsigned long) (~0);
+  context_values.foreground=0;
+  context_values.line_width=(int) draw_info->line_width;
+  draw_context=XCreateGC(display,root_window,(unsigned long)
+    (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,(unsigned long) (~0));
+  (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,x,y,&draw_image->background_color,
+    &image->exception);
+  if (SetImageStorageClass(draw_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  draw_image->matte=MagickTrue;
+  exception=(&image->exception);
+  for (y=0; y < (int) draw_image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=QueueAuthenticPixels(draw_image,0,y,draw_image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) draw_image->columns; x++)
+    {
+      if (XGetPixel(draw_ximage,x,y) == 0)
+        {
+          /*
+            Set this pixel to the background color.
+          */
+          *q=draw_image->background_color;
+          q->opacity=(Quantum) (draw_info->stencil == OpaqueStencil ?
+            TransparentOpacity : OpaqueOpacity);
+        }
+      else
+        {
+          /*
+            Set this pixel to the pen color.
+          */
+          q->red=ScaleShortToQuantum(pixel->pen_color.red);
+          q->green=ScaleShortToQuantum(pixel->pen_color.green);
+          q->blue=ScaleShortToQuantum(pixel->pen_color.blue);
+          q->opacity=(Quantum) (draw_info->stencil == OpaqueStencil ?
+            OpaqueOpacity : TransparentOpacity);
+        }
+      q++;
+    }
+    if (SyncAuthenticPixels(draw_image,exception) == MagickFalse)
+      break;
+  }
+  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) FormatMagickString(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.
+  */
+  for (y=0; y < (int) draw_image->rows; y++)
+  {
+    register long
+      x;
+
+    register PixelPacket
+      *__restrict q;
+
+    q=GetAuthenticPixels(draw_image,0,y,draw_image->columns,1,exception);
+    if (q == (PixelPacket *) NULL)
+      break;
+    for (x=0; x < (long) draw_image->columns; x++)
+    {
+      if (q->opacity != (Quantum) TransparentOpacity)
+        q->opacity=OpaqueOpacity;
+      q++;
+    }
+    if (SyncAuthenticPixels(draw_image,exception) == MagickFalse)
+      break;
+  }
+  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
+  if (draw_info->stencil == TransparentStencil)
+    (void) CompositeImage(image,CopyOpacityCompositeOp,draw_image,x,y);
+  else
+    {
+      matte=image->matte;
+      (void) CompositeImage(image,OverCompositeOp,draw_image,x,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);
+  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=(unsigned long) (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=(unsigned long) (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=(unsigned long) (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                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetPixelPacket() initializes the PixelPacket structure.
+%
+%  The format of the XGetPixelPacket method is:
+%
+%      void XGetPixelPacket(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 XGetPixelPacket(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 long
+    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=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 < (long) image->colors; i++)
+            pixel->pixels[i]=
+              XGammaPixel(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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) FormatMagickString(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
+    *cwd,
+    *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) atoi(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) atoi(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) ParseMagickOption(MagickGravityOptions,
+    MagickFalse,resource_value);
+  cwd=getcwd(resource_info->home_directory,MaxTextExtent);
+  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) atoi(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) atoi(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"quantum",(char *) "1");
+  resource_info->quantum=atoi(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) atol(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) FormatMagickString(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) FormatMagickString(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.opacity=OpaqueOpacity;
+  (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;
+
+  IndexPacket
+    index;
+
+  int
+    display_height,
+    display_width,
+    id,
+    x_offset,
+    y_offset;
+
+  RectangleInfo
+    crop_info;
+
+  register IndexPacket
+    *indexes;
+
+  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=(long) x_offset;
+  crop_info.y=(long) y_offset;
+  crop_info.width=(unsigned long) window_attributes.width;
+  crop_info.height=(unsigned long) window_attributes.height;
+  if (borders != MagickFalse)
+    {
+      /*
+        Include border in image.
+      */
+      crop_info.x-=(long) window_attributes.border_width;
+      crop_info.y-=(long) window_attributes.border_width;
+      crop_info.width+=(unsigned long) (window_attributes.border_width << 1);
+      crop_info.height+=(unsigned long) (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=(unsigned long) (display_width-crop_info.x);
+  display_height=XDisplayHeight(display,XDefaultScreen(display));
+  if ((int) (crop_info.y+crop_info.height) > display_height)
+    crop_info.height=(unsigned long) (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)
+    {
+      ColormapInfo
+        *next;
+
+      ExceptionInfo
+        *exception;
+
+      Image
+        *composite_image,
+        *image;
+
+      int
+        y;
+
+      MagickBooleanType
+        import;
+
+      register int
+        j,
+        x;
+
+      register PixelPacket
+        *__restrict q;
+
+      register unsigned long
+        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=(unsigned long) i;
+                    colors[i].pad='\0';
+                  }
+                else
+                  {
+                    unsigned long
+                      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=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=(unsigned long) ximage->width;
+        composite_image->rows=(unsigned long) ximage->height;
+        exception=(&composite_image->exception);
+        switch (composite_image->storage_class)
+        {
+          case DirectClass:
+          default:
+          {
+            register unsigned long
+              color,
+              index;
+
+            unsigned long
+              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=QueueAuthenticPixels(composite_image,0,y,
+                  composite_image->columns,1,exception);
+                if (q == (PixelPacket *) NULL)
+                  break;
+                for (x=0; x < (int) composite_image->columns; x++)
+                {
+                  pixel=XGetPixel(ximage,x,y);
+                  index=(pixel >> red_shift) & red_mask;
+                  q->red=ScaleShortToQuantum(colors[index].red);
+                  index=(pixel >> green_shift) & green_mask;
+                  q->green=ScaleShortToQuantum(colors[index].green);
+                  index=(pixel >> blue_shift) & blue_mask;
+                  q->blue=ScaleShortToQuantum(colors[index].blue);
+                  q++;
+                }
+                if (SyncAuthenticPixels(composite_image,exception) == MagickFalse)
+                  break;
+              }
+            else
+              for (y=0; y < (int) composite_image->rows; y++)
+              {
+                q=QueueAuthenticPixels(composite_image,0,y,
+                  composite_image->columns,1,exception);
+                if (q == (PixelPacket *) 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;
+                  q->red=ScaleShortToQuantum((unsigned short) color);
+                  color=(pixel >> green_shift) & green_mask;
+                  color=(65535UL*color)/green_mask;
+                  q->green=ScaleShortToQuantum((unsigned short) color);
+                  color=(pixel >> blue_shift) & blue_mask;
+                  color=(65535UL*color)/blue_mask;
+                  q->blue=ScaleShortToQuantum((unsigned short) color);
+                  q++;
+                }
+                if (SyncAuthenticPixels(composite_image,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=QueueAuthenticPixels(composite_image,0,y,composite_image->columns,1,exception);
+              if (q == (PixelPacket *) NULL)
+                break;
+              indexes=GetAuthenticIndexQueue(composite_image);
+              for (x=0; x < (int) composite_image->columns; x++)
+              {
+                index=(IndexPacket) XGetPixel(ximage,x,y);
+                indexes[x]=index;
+                *q++=composite_image->colormap[(long) index];
+              }
+              if (SyncAuthenticPixels(composite_image,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+        }
+        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,x_offset,
+          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=(unsigned long) 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=(unsigned long) (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=x;
+      crop_info.y=y;
+      crop_info.width=(unsigned long) window_attributes.width;
+      crop_info.height=(unsigned long) window_attributes.height;
+      if (ximage_info->borders)
+        {
+          /*
+            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(__WINDOWS__)
+  (void) XSynchronize(display,IsWindows95());
+#endif
+  if (IsEventLogging())
+    {
+      (void) XSynchronize(display,MagickTrue);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Version: %s",
+        GetMagickVersion((unsigned long *) 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;
+      height=(unsigned int) 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) &&
+        ((long) width <= XDisplayWidth(display,window->screen)) &&
+        ((long) 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=1;
+          context_values.foreground=0;
+          graphics_context=XCreateGC(display,window->matte_pixmap,
+            (unsigned long) (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)
+{
+  Image
+    *canvas;
+
+  int
+    y;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *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 ((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) FormatMagickString(size,MaxTextExtent,"%lux%lu",image->columns,
+        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;
+  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) ((PixelIntensityToQuantum(
+        &canvas->colormap[0])) < ((Quantum) QuantumRange/2) ? 1 : 0);
+      if (canvas->colors == 2)
+        polarity=PixelIntensity(&canvas->colormap[0]) <
+          PixelIntensity(&canvas->colormap[1]);
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(canvas);
+        bit=0;
+        byte=0;
+        for (x=0; x < (int) canvas->columns; x++)
+        {
+          byte>>=1;
+          if (indexes[x] == (IndexPacket) polarity)
+            byte|=foreground;
+          else
+            byte|=background;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+        }
+        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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]] & 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;
+                }
+              }
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]] & 0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) pixel;
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]];
+              *q++=(unsigned char) pixel;
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          register int
+            k;
+
+          register unsigned int
+            bytes_per_pixel;
+
+          unsigned char
+            channel[sizeof(unsigned long)];
+
+          /*
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]];
+              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];
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(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++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(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++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(map_info,p);
+              *q++=(unsigned char) pixel;
+              p++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                  &canvas->exception);
+                if (p == (const PixelPacket *) 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(p->blue));
+                      *q++=ScaleQuantumToChar(XGreenGamma(p->green));
+                      *q++=ScaleQuantumToChar(XRedGamma(p->red));
+                      *q++=0;
+                      p++;
+                    }
+                    continue;
+                  }
+                for (x=(int) canvas->columns-1; x >= 0; x--)
+                {
+                  *q++=ScaleQuantumToChar((Quantum) p->blue);
+                  *q++=ScaleQuantumToChar((Quantum) p->green);
+                  *q++=ScaleQuantumToChar((Quantum) p->red);
+                  *q++=0;
+                  p++;
+                }
+              }
+            }
+          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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                    &canvas->exception);
+                  if (p == (const PixelPacket *) 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(p->red));
+                        *q++=ScaleQuantumToChar(XGreenGamma(p->green));
+                        *q++=ScaleQuantumToChar(XBlueGamma(p->blue));
+                        *q++=0;
+                        p++;
+                      }
+                      continue;
+                    }
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    *q++=ScaleQuantumToChar((Quantum) p->red);
+                    *q++=ScaleQuantumToChar((Quantum) p->green);
+                    *q++=ScaleQuantumToChar((Quantum) p->blue);
+                    *q++=0;
+                    p++;
+                  }
+                }
+              }
+            else
+              {
+                register int
+                  k;
+
+                register unsigned int
+                  bytes_per_pixel;
+
+                unsigned char
+                  channel[sizeof(unsigned long)];
+
+                /*
+                  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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                    &canvas->exception);
+                  if (p == (PixelPacket *) NULL)
+                    break;
+                  for (x=0; x < (long) canvas->columns; x++)
+                  {
+                    pixel=XGammaPixel(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++;
+                  }
+                  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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte>>=1;
+          if (p->opacity > (long) (QuantumRange/2))
+            byte|=0x80;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p++;
+        }
+        if (bit != 0)
+          *q=byte >> (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  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)
+{
+  Image
+    *canvas;
+
+  int
+    y;
+
+  register int
+    x;
+
+  register const IndexPacket
+    *indexes;
+
+  register const PixelPacket
+    *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 ((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) FormatMagickString(size,MaxTextExtent,"%lux%lu",image->columns,
+        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;
+  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) ((PixelIntensityToQuantum(
+        &canvas->colormap[0])) < ((Quantum) QuantumRange/2) ? 1 : 0);
+      if (canvas->colors == 2)
+        polarity=PixelIntensity(&canvas->colormap[0]) <
+          PixelIntensity(&canvas->colormap[1]);
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        indexes=GetVirtualIndexQueue(canvas);
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte<<=1;
+          if (indexes[x] == (IndexPacket) polarity)
+            byte|=foreground;
+          else
+            byte|=background;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+        }
+        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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]] & 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;
+                }
+              }
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]] & 0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) pixel;
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]];
+              *q++=(unsigned char) pixel;
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          register int
+            k;
+
+          register unsigned int
+            bytes_per_pixel;
+
+          unsigned char
+            channel[sizeof(unsigned long)];
+
+          /*
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            indexes=GetVirtualIndexQueue(canvas);
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(long) indexes[x]];
+              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];
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            nibble=0;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(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++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            nibble=0;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(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++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+            if (p == (const PixelPacket *) NULL)
+              break;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(map_info,p);
+              *q++=(unsigned char) pixel;
+              p++;
+            }
+            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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                  &canvas->exception);
+                if (p == (const PixelPacket *) 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(p->red));
+                      *q++=ScaleQuantumToChar(XGreenGamma(p->green));
+                      *q++=ScaleQuantumToChar(XBlueGamma(p->blue));
+                      p++;
+                    }
+                    continue;
+                  }
+                for (x=(int) canvas->columns-1; x >= 0; x--)
+                {
+                  *q++=0;
+                  *q++=ScaleQuantumToChar((Quantum) p->red);
+                  *q++=ScaleQuantumToChar((Quantum) p->green);
+                  *q++=ScaleQuantumToChar((Quantum) p->blue);
+                  p++;
+                }
+              }
+            }
+          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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                    &canvas->exception);
+                  if (p == (const PixelPacket *) 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(p->blue));
+                        *q++=ScaleQuantumToChar(XGreenGamma(p->green));
+                        *q++=ScaleQuantumToChar(XRedGamma(p->red));
+                        p++;
+                      }
+                      continue;
+                    }
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    *q++=0;
+                    *q++=ScaleQuantumToChar((Quantum) p->blue);
+                    *q++=ScaleQuantumToChar((Quantum) p->green);
+                    *q++=ScaleQuantumToChar((Quantum) p->red);
+                    p++;
+                  }
+                }
+              }
+            else
+              {
+                register int
+                  k;
+
+                register unsigned int
+                  bytes_per_pixel;
+
+                unsigned char
+                  channel[sizeof(unsigned long)];
+
+                /*
+                  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=GetVirtualPixels(canvas,0,y,canvas->columns,1,
+                    &canvas->exception);
+                  if (p == (const PixelPacket *) NULL)
+                    break;
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    pixel=XGammaPixel(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++;
+                  }
+                  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=GetVirtualPixels(canvas,0,y,canvas->columns,1,&canvas->exception);
+        if (p == (const PixelPacket *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte<<=1;
+          if (p->opacity > (long) (QuantumRange/2))
+            byte|=0x01;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p++;
+        }
+        if (bit != 0)
+          *q=byte << (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  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;
+
+  long
+    n;
+
+  MagickPixelPacket
+    pixel;
+
+  register int
+    x;
+
+  register long
+    i;
+
+  register unsigned char
+    *p,
+    *q;
+
+  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 < (long) 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) FormatMagickString(windows->magnify.name,MaxTextExtent,
+        "Magnify %luX",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 < (long) 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 < (long) 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 < (long) 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 < (long) 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=(long) windows->magnify.width >> 1;
+      highlight_info.y=(long) 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,windows->magnify.x,
+    windows->magnify.y,&pixel,&windows->image.image->exception);
+  (void) FormatMagickString(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,IndexChannel,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 unsigned long x,
+  const unsigned long 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 IndexPacket
+    *indexes;
+
+  register long
+    i;
+
+  Status
+    status;
+
+  unsigned long
+    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).
+      */
+      XGetPixelPacket(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 PixelPacket
+              *__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 != (PixelPacket *) NULL)
+              {
+                for (i=0; i < (long) number_colors; i++)
+                {
+                  q->red=(Quantum) 0;
+                  if (map_info->red_max != 0)
+                    q->red=ScaleXToQuantum((unsigned long) (i/
+                      map_info->red_mult),map_info->red_max);
+                  q->green=(Quantum) 0;
+                  if (map_info->green_max != 0)
+                    q->green=ScaleXToQuantum((unsigned long) ((i/
+                      map_info->green_mult) % (map_info->green_max+1)),
+                      map_info->green_max);
+                  q->blue=(Quantum) 0;
+                  if (map_info->blue_max != 0)
+                    q->blue=ScaleXToQuantum((unsigned long) (i %
+                      map_info->green_mult),map_info->blue_max);
+                  q->opacity=(Quantum) TransparentOpacity;
+                  q++;
+                }
+                (void) SyncAuthenticPixels(affinity_image,exception);
+                (void) RemapImage(resource_info->quantize_info,image,
+                  affinity_image);
+              }
+            XGetPixelPacket(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=(unsigned long) 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);
+  XGetPixelPacket(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 < (long) 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)
+        {
+          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 < (long) 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;
+          }
+          for (y=0; y < (int) image->rows; y++)
+          {
+            register long
+              x;
+
+            register PixelPacket
+              *__restrict q;
+
+            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+            if (q == (PixelPacket *) NULL)
+              break;
+            indexes=GetAuthenticIndexQueue(image);
+            for (x=(long) image->columns-1; x >= 0; x--)
+              diversity[(long) indexes[x]].count++;
+          }
+          /*
+            Sort colors by decreasing intensity.
+          */
+          qsort((void *) diversity,image->colors,sizeof(*diversity),
+            IntensityCompare);
+          for (i=0; i < (long) image->colors; )
+          {
+            diversity[i].count<<=4;  /* increase this colors popularity */
+            i+=MagickMax((long) (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 < (long) 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=(unsigned long) 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 < (long) 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 < (long) 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 < (long) 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 < (long) 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 < (long) 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=(unsigned long) 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 < (long) number_colors; i++)
+        {
+          color.blue=(unsigned short) 0;
+          if (map_info->blue_max != 0)
+            color.blue=(unsigned short) ((unsigned long)
+              ((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 < (long) number_colors; i++)
+        {
+          color.red=(unsigned short) 0;
+          if (map_info->red_max != 0)
+            color.red=(unsigned short) ((unsigned long)
+              ((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) ((unsigned long)
+              ((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) ((unsigned long)
+              ((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 < (long) 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=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=(long) 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) FormatMagickString(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,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,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) FormatMagickString(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)) ;
+    }
+  /*
+    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)
+    {
+#if defined(MAGICKCORE_HAVE_SHAPE)
+      if (window->shape != MagickFalse)
+        XShapeCombineMask(display,window->id,ShapeBounding,0,0,
+          window->matte_pixmap,ShapeSet);
+#endif
+      (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,(unsigned long) (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=x_offset;
+        crop_info->y=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=event.xmotion.x;
+        crop_info->y=event.xmotion.y;
+        /*
+          Check boundary conditions.
+        */
+        if ((int) crop_info->x < x_offset)
+          crop_info->width=(unsigned int) (x_offset-crop_info->x);
+        else
+          {
+            crop_info->width=(unsigned int) (crop_info->x-x_offset);
+            crop_info->x=x_offset;
+          }
+        if ((int) crop_info->y < y_offset)
+          crop_info->height=(unsigned int) (y_offset-crop_info->y);
+        else
+          {
+            crop_info->height=(unsigned int) (crop_info->y-y_offset);
+            crop_info->y=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
+    *value;
+
+  XrmDatabase
+    preferences_database;
+
+  /*
+    Save user preferences to the client configuration file.
+  */
+  assert(resource_info != (XResourceInfo *) NULL);
+  preferences_database=XrmGetStringDatabase("");
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.backdrop",
+    GetClientName());
+  value=resource_info->backdrop ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.colormap",
+    GetClientName());
+  value=resource_info->colormap == SharedColormap ? "Shared" : "Private";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.confirmExit",
+    GetClientName());
+  value=resource_info->confirm_exit ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.confirmEdit",
+    GetClientName());
+  value=resource_info->confirm_edit ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.displayWarnings",
+    GetClientName());
+  value=resource_info->display_warnings ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.dither",
+    GetClientName());
+  value=resource_info->quantize_info->dither ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.gammaCorrect",
+    GetClientName());
+  value=resource_info->gamma_correct ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.undoCache",
+    GetClientName());
+  (void) FormatMagickString(cache,MaxTextExtent,"%lu",
+    resource_info->undo_cache);
+  XrmPutStringResource(&preferences_database,specifier,cache);
+  (void) FormatMagickString(specifier,MaxTextExtent,"%s.usePixmap",
+    GetClientName());
+  value=resource_info->use_pixmap ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatMagickString(filename,MaxTextExtent,"%s%src",
+    X11_PREFERENCES_PATH,GetClientName());
+  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 unsigned long 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(id);
+  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 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/magick/xwindow.h b/magick/xwindow.h
new file mode 100644
index 0000000..ec8ba63
--- /dev/null
+++ b/magick/xwindow.h
@@ -0,0 +1,45 @@
+/*
+  Copyright 1999-2009 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