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);
+}