]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/effect.c
(no commit message)
[imagemagick] / MagickCore / effect.c
index 7a612aaa2ba7ab35997df6b4fc21912456e9ecff..26492ee9bef0116ab0e27f2608ad33b5d99db8f9 100644 (file)
@@ -56,6 +56,7 @@
 #include "MagickCore/effect.h"
 #include "MagickCore/fx.h"
 #include "MagickCore/gem.h"
+#include "MagickCore/gem-private.h"
 #include "MagickCore/geometry.h"
 #include "MagickCore/image-private.h"
 #include "MagickCore/list.h"
 %  The format of the AdaptiveBlurImage method is:
 %
 %      Image *AdaptiveBlurImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 
 MagickExport MagickBooleanType AdaptiveLevelImage(Image *image,
-  const char *levels)
+  const char *levels,ExceptionInfo *exception)
 {
   double
     black_point,
@@ -158,14 +161,15 @@ MagickExport MagickBooleanType AdaptiveLevelImage(Image *image,
   if ((flags & SigmaValue) == 0)
     white_point=(double) QuantumRange-black_point;
   if ((flags & AspectValue ) == 0)
-    status=LevelImage(image,black_point,white_point,gamma);
+    status=LevelImage(image,black_point,white_point,gamma,exception);
   else
-    status=LevelizeImage(image,black_point,white_point,gamma);
+    status=LevelizeImage(image,black_point,white_point,gamma,exception);
   return(status);
 }
 
 MagickExport Image *AdaptiveBlurImage(const Image *image,
-  const double radius,const double sigma,ExceptionInfo *exception)
+  const double radius,const double sigma,const double bias,
+  ExceptionInfo *exception)
 {
 #define AdaptiveBlurImageTag  "Convolve/Image"
 #define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
@@ -190,9 +194,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -217,29 +218,28 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
     return((Image *) NULL);
   if (fabs(sigma) <= MagickEpsilon)
     return(blur_image);
-  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(blur_image,DirectClass,exception) == 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);
+  edge_image=EdgeImage(image,radius,sigma,exception);
   if (edge_image == (Image *) NULL)
     {
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
-  (void) AdaptiveLevelImage(edge_image,"20%,95%");
-  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
+  (void) AdaptiveLevelImage(edge_image,"20%,95%",exception);
+  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,bias,exception);
   if (gaussian_image != (Image *) NULL)
     {
       edge_image=DestroyImage(edge_image);
       edge_image=gaussian_image;
     }
-  (void) AdaptiveLevelImage(edge_image,"10%,95%");
+  (void) AdaptiveLevelImage(edge_image,"10%,95%",exception);
   /*
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
@@ -291,8 +291,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
   image_view=AcquireCacheView(image);
   edge_view=AcquireCacheView(edge_image);
   blur_view=AcquireCacheView(blur_image);
@@ -302,7 +300,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   for (y=0; y < (ssize_t) blur_image->rows; y++)
   {
     register const Quantum
-      *restrict p,
       *restrict r;
 
     register Quantum
@@ -316,80 +313,115 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
     r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if ((r == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+    if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) blur_image->columns; x++)
     {
-      PixelInfo
-        pixel;
-
-      MagickRealType
-        alpha,
-        gamma;
-
-      register const double
-        *restrict k;
+      register const Quantum
+        *restrict p;
 
       register ssize_t
-        i,
-        u,
-        v;
+        i;
 
-      gamma=0.0;
-      i=(ssize_t) ceil((double) width*QuantumScale*
+      ssize_t
+        center,
+        j;
+
+      j=(ssize_t) ceil((double) width*QuantumScale*
         GetPixelIntensity(edge_image,r)-0.5);
-      if (i < 0)
-        i=0;
+      if (j < 0)
+        j=0;
       else
-        if (i > (ssize_t) width)
-          i=(ssize_t) width;
-      if ((i & 0x01) != 0)
-        i--;
-      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
-        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+        if (j > (ssize_t) width)
+          j=(ssize_t) width;
+      if ((j & 0x01) != 0)
+        j--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
+        (ssize_t) ((width-j)/2L),width-j,width-j,exception);
       if (p == (const Quantum *) NULL)
         break;
-      pixel=bias;
-      k=kernel[i];
-      for (v=0; v < (ssize_t) (width-i); v++)
+      center=(ssize_t) GetPixelChannels(image)*(width-j)*
+        ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2L);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        for (u=0; u < (ssize_t) (width-i); u++)
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          blur_traits,
+          traits;
+
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
+          }
+        k=kernel[j];
+        pixels=p;
+        pixel=bias;
+        gamma=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (v=0; v < (ssize_t) (width-j); v++)
+            {
+              for (u=0; u < (ssize_t) (width-j); u++)
+              {
+                pixel+=(*k)*pixels[i];
+                gamma+=(*k);
+                k++;
+                pixels+=GetPixelChannels(image);
+              }
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        for (v=0; v < (ssize_t) (width-j); v++)
         {
-          alpha=1.0;
-          if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->matte != MagickFalse))
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
-          gamma+=(*k)*alpha;
-          k++;
-          p+=GetPixelChannels(image);
+          for (u=0; u < (ssize_t) (width-j); u++)
+          {
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            pixel+=(*k)*alpha*pixels[i];
+            gamma+=(*k)*alpha;
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
-      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
       q+=GetPixelChannels(blur_image);
       r+=GetPixelChannels(edge_image);
     }
@@ -401,7 +433,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_AdaptiveSharpenImage)
+  #pragma omp critical (MagickCore_AdaptiveBlurImage)
 #endif
         proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress++,
           image->rows);
@@ -442,7 +474,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
 %  The format of the AdaptiveSharpenImage method is:
 %
 %      Image *AdaptiveSharpenImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -453,11 +485,13 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
 #define AdaptiveSharpenImageTag  "Convolve/Image"
 #define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
@@ -482,9 +516,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -509,29 +540,28 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
     return((Image *) NULL);
   if (fabs(sigma) <= MagickEpsilon)
     return(sharp_image);
-  if (SetImageStorageClass(sharp_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(sharp_image,DirectClass,exception) == 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);
+  edge_image=EdgeImage(image,radius,sigma,exception);
   if (edge_image == (Image *) NULL)
     {
       sharp_image=DestroyImage(sharp_image);
       return((Image *) NULL);
     }
-  (void) AdaptiveLevelImage(edge_image,"20%,95%");
-  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
+  (void) AdaptiveLevelImage(edge_image,"20%,95%",exception);
+  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,bias,exception);
   if (gaussian_image != (Image *) NULL)
     {
       edge_image=DestroyImage(edge_image);
       edge_image=gaussian_image;
     }
-  (void) AdaptiveLevelImage(edge_image,"10%,95%");
+  (void) AdaptiveLevelImage(edge_image,"10%,95%",exception);
   /*
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
@@ -583,8 +613,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
   image_view=AcquireCacheView(image);
   edge_view=AcquireCacheView(edge_image);
   sharp_view=AcquireCacheView(sharp_image);
@@ -594,7 +622,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   for (y=0; y < (ssize_t) sharp_image->rows; y++)
   {
     register const Quantum
-      *restrict p,
       *restrict r;
 
     register Quantum
@@ -615,73 +642,108 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
       }
     for (x=0; x < (ssize_t) sharp_image->columns; x++)
     {
-      PixelInfo
-        pixel;
-
-      MagickRealType
-        alpha,
-        gamma;
-
-      register const double
-        *restrict k;
+      register const Quantum
+        *restrict p;
 
       register ssize_t
-        i,
-        u,
-        v;
+        i;
+
+      ssize_t
+        center,
+        j;
 
-      gamma=0.0;
-      i=(ssize_t) ceil((double) width*QuantumScale*
+      j=(ssize_t) ceil((double) width*QuantumScale*
         GetPixelIntensity(edge_image,r)-0.5);
-      if (i < 0)
-        i=0;
+      if (j < 0)
+        j=0;
       else
-        if (i > (ssize_t) width)
-          i=(ssize_t) width;
-      if ((i & 0x01) != 0)
-        i--;
-      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
-        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+        if (j > (ssize_t) width)
+          j=(ssize_t) width;
+      if ((j & 0x01) != 0)
+        j--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
+        (ssize_t) ((width-j)/2L),width-j,width-j,exception);
       if (p == (const Quantum *) NULL)
         break;
-      k=kernel[i];
-      pixel=bias;
-      for (v=0; v < (ssize_t) (width-i); v++)
+      center=(ssize_t) GetPixelChannels(image)*(width-j)*
+        ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        for (u=0; u < (ssize_t) (width-i); u++)
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          sharp_traits,
+          traits;
+
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        sharp_traits=GetPixelChannelMapTraits(sharp_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (sharp_traits == UndefinedPixelTrait))
+          continue;
+        if ((sharp_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(sharp_image,channel,p[center+i],q);
+            continue;
+          }
+        k=kernel[j];
+        pixels=p;
+        pixel=bias;
+        gamma=0.0;
+        if ((sharp_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (v=0; v < (ssize_t) (width-j); v++)
+            {
+              for (u=0; u < (ssize_t) (width-j); u++)
+              {
+                pixel+=(*k)*pixels[i];
+                gamma+=(*k);
+                k++;
+                pixels+=GetPixelChannels(image);
+              }
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        for (v=0; v < (ssize_t) (width-j); v++)
         {
-          alpha=1.0;
-          if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->matte != MagickFalse))
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
-          gamma+=(*k)*alpha;
-          k++;
-          p+=GetPixelChannels(image);
+          for (u=0; u < (ssize_t) (width-j); u++)
+          {
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            pixel+=(*k)*alpha*pixels[i];
+            gamma+=(*k)*alpha;
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
       }
-      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(sharp_image,ClampToQuantum(gamma*pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(sharp_image,ClampToQuantum(gamma*pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(sharp_image,ClampToQuantum(gamma*pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(sharp_image,ClampToQuantum(gamma*pixel.black),q);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelAlpha(sharp_image,ClampToQuantum(pixel.alpha),q);
       q+=GetPixelChannels(sharp_image);
       r+=GetPixelChannels(edge_image);
     }
@@ -737,7 +799,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
 %  The format of the BlurImage method is:
 %
 %      Image *BlurImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -748,6 +810,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
 %
 %    o sigma: the standard deviation of the Gaussian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -788,7 +852,7 @@ static double *GetBlurKernel(const size_t width,const double sigma)
 }
 
 MagickExport Image *BlurImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
 #define BlurImageTag  "Blur/Image"
 
@@ -808,9 +872,6 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -818,6 +879,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     width;
 
   ssize_t
+    center,
     x,
     y;
 
@@ -835,9 +897,8 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     return((Image *) NULL);
   if (fabs(sigma) <= MagickEpsilon)
     return(blur_image);
-  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&blur_image->exception);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
@@ -877,14 +938,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
+  center=(ssize_t) GetPixelChannels(image)*(width/2L);
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
 #endif
-  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
       *restrict p;
@@ -906,101 +966,77 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register const Quantum
-        *restrict kernel_pixels;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      kernel_pixels=p;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) ||
-          (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
-          {
-            pixel.red+=(*k)*GetPixelRed(image,kernel_pixels);
-            pixel.green+=(*k)*GetPixelGreen(image,kernel_pixels);
-            pixel.blue+=(*k)*GetPixelBlue(image,kernel_pixels);
-            if (image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*GetPixelBlack(image,kernel_pixels);
-            k++;
-            kernel_pixels+=GetPixelChannels(image);
-          }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-            }
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
 
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
+        register ssize_t
+          u;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            alpha=(MagickRealType) (QuantumScale*
-              GetPixelAlpha(image,kernel_pixels));
-            pixel.red+=(*k)*alpha*GetPixelRed(image,kernel_pixels);
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,kernel_pixels);
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,kernel_pixels);
-            if (image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*alpha*GetPixelBlack(image,kernel_pixels);
-            gamma+=(*k)*alpha;
-            k++;
-            kernel_pixels+=GetPixelChannels(image);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixels=p;
+        pixel=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (u=0; u < (ssize_t) width; u++)
             {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+              pixel+=(*k)*pixels[i];
+              k++;
+              pixels+=GetPixelChannels(image);
             }
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        gamma=0.0;
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+          pixel+=(*k)*alpha*pixels[i];
+          gamma+=(*k)*alpha;
+          k++;
+          pixels+=GetPixelChannels(image);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
@@ -1030,7 +1066,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
 #endif
-  for (x=0; x < (ssize_t) blur_image->columns; x++)
+  for (x=0; x < (ssize_t) image->columns; x++)
   {
     register const Quantum
       *restrict p;
@@ -1051,101 +1087,78 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         status=MagickFalse;
         continue;
       }
-    for (y=0; y < (ssize_t) blur_image->rows; y++)
+    for (y=0; y < (ssize_t) image->rows; y++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register const Quantum
-        *restrict kernel_pixels;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      kernel_pixels=p;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) ||
-          (blur_image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
-          {
-            pixel.red+=(*k)*GetPixelRed(blur_image,kernel_pixels);
-            pixel.green+=(*k)*GetPixelGreen(blur_image,kernel_pixels);
-            pixel.blue+=(*k)*GetPixelBlue(blur_image,kernel_pixels);
-            if (blur_image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*GetPixelBlack(blur_image,kernel_pixels);
-            k++;
-            kernel_pixels+=GetPixelChannels(blur_image);
-          }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(blur_image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-            }
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
+        register const double
+          *restrict k;
 
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        traits=GetPixelChannelMapTraits(blur_image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(blur_image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            alpha=(MagickRealType) (QuantumScale*
-              GetPixelAlpha(blur_image,kernel_pixels));
-            pixel.red+=(*k)*alpha*GetPixelRed(blur_image,kernel_pixels);
-            pixel.green+=(*k)*alpha*GetPixelGreen(blur_image,kernel_pixels);
-            pixel.blue+=(*k)*alpha*GetPixelBlue(blur_image,kernel_pixels);
-            if (blur_image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*alpha*GetPixelBlack(blur_image,kernel_pixels);
-            gamma+=(*k)*alpha;
-            k++;
-            kernel_pixels+=GetPixelChannels(blur_image);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixels=p;
+        pixel=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (u=0; u < (ssize_t) width; u++)
             {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(blur_image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+              pixel+=(*k)*pixels[i];
+              k++;
+              pixels+=GetPixelChannels(blur_image);
             }
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        gamma=0.0;
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          alpha=(MagickRealType) (QuantumScale*
+            GetPixelAlpha(blur_image,pixels));
+          pixel+=(*k)*alpha*pixels[i];
+          gamma+=(*k)*alpha;
+          k++;
+          pixels+=GetPixelChannels(blur_image);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(blur_image);
       q+=GetPixelChannels(blur_image);
     }
@@ -1220,6 +1233,7 @@ MagickExport Image *ConvolveImage(const Image *image,
     progress;
 
   ssize_t
+    center,
     y;
 
   /*
@@ -1237,9 +1251,8 @@ MagickExport Image *ConvolveImage(const Image *image,
     exception);
   if (convolve_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(convolve_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(convolve_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&convolve_image->exception);
       convolve_image=DestroyImage(convolve_image);
       return((Image *) NULL);
     }
@@ -1277,9 +1290,14 @@ MagickExport Image *ConvolveImage(const Image *image,
       }
       message=DestroyString(message);
     }
+  status=AccelerateConvolveImage(image,kernel_info,convolve_image,exception);
+  if (status == MagickTrue)
+    return(convolve_image);
   /*
     Convolve image.
   */
+  center=(ssize_t) GetPixelChannels(image)*(image->columns+kernel_info->width)*
+    (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2L);
   status=MagickTrue;
   progress=0;
   image_view=AcquireCacheView(image);
@@ -1298,9 +1316,6 @@ MagickExport Image *ConvolveImage(const Image *image,
     register ssize_t
       x;
 
-    ssize_t
-      center;
-
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) kernel_info->width/2L),y-
@@ -1313,8 +1328,6 @@ MagickExport Image *ConvolveImage(const Image *image,
         status=MagickFalse;
         continue;
       }
-    center=GetPixelChannels(image)*(image->columns+kernel_info->width)*
-      (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       register ssize_t
@@ -1347,23 +1360,20 @@ MagickExport Image *ConvolveImage(const Image *image,
           v;
 
         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
-        if (traits == UndefinedPixelTrait)
-          continue;
         channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
         convolve_traits=GetPixelChannelMapTraits(convolve_image,channel);
-        if (convolve_traits == UndefinedPixelTrait)
+        if ((traits == UndefinedPixelTrait) ||
+            (convolve_traits == UndefinedPixelTrait))
           continue;
         if ((convolve_traits & CopyPixelTrait) != 0)
           {
-            q[channel]=p[center+i];
+            SetPixelChannel(convolve_image,channel,p[center+i],q);
             continue;
           }
         k=kernel_info->values;
         pixels=p;
         pixel=kernel_info->bias;
-        if (((convolve_traits & BlendPixelTrait) == 0) ||
-            (GetPixelAlphaTraits(image) == UndefinedPixelTrait) ||
-            (image->matte == MagickFalse))
+        if ((convolve_traits & BlendPixelTrait) == 0)
           {
             /*
               No alpha blending.
@@ -1378,7 +1388,7 @@ MagickExport Image *ConvolveImage(const Image *image,
               }
               pixels+=image->columns*GetPixelChannels(image);
             }
-            q[channel]=ClampToQuantum(pixel);
+            SetPixelChannel(convolve_image,channel,ClampToQuantum(pixel),q);
             continue;
           }
         /*
@@ -1398,7 +1408,7 @@ MagickExport Image *ConvolveImage(const Image *image,
           pixels+=image->columns*GetPixelChannels(image);
         }
         gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-        q[channel]=ClampToQuantum(gamma*pixel);
+        SetPixelChannel(convolve_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(convolve_image);
@@ -1566,16 +1576,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
   MagickBooleanType
     status;
 
-  register ssize_t
-    i;
-
   Quantum
     *restrict buffers,
     *restrict pixels;
 
+  register ssize_t
+    i;
+
   size_t
-    length,
-    number_channels;
+    length;
 
   static const ssize_t
     X[4] = {0, 1, 1,-1},
@@ -1590,13 +1599,12 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     (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);
+  despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
   if (despeckle_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(despeckle_image,DirectClass) == MagickFalse)
+  status=SetImageStorageClass(despeckle_image,DirectClass,exception);
+  if (status == MagickFalse)
     {
-      InheritException(exception,&despeckle_image->exception);
       despeckle_image=DestroyImage(despeckle_image);
       return((Image *) NULL);
     }
@@ -1619,11 +1627,17 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     Reduce speckle in the image.
   */
   status=MagickTrue;
-  number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
   image_view=AcquireCacheView(image);
   despeckle_view=AcquireCacheView(despeckle_image);
-  for (i=0; i < (ssize_t) number_channels; i++)
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
+    PixelChannel
+       channel;
+
+    PixelTrait
+      despeckle_traits,
+      traits;
+
     register Quantum
       *buffer,
       *pixel;
@@ -1638,6 +1652,14 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 
     if (status == MagickFalse)
       continue;
+    traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+    channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+    despeckle_traits=GetPixelChannelMapTraits(despeckle_image,channel);
+    if ((traits == UndefinedPixelTrait) ||
+        (despeckle_traits == UndefinedPixelTrait))
+      continue;
+    if ((despeckle_traits & CopyPixelTrait) != 0)
+      continue;
     pixel=pixels;
     (void) ResetMagickMemory(pixel,0,length*sizeof(*pixel));
     buffer=buffers;
@@ -1649,21 +1671,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 
       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
       if (p == (const Quantum *) NULL)
-        break;
+        {
+          status=MagickFalse;
+          continue;
+        }
       j++;
       for (x=0; x < (ssize_t) image->columns; x++)
       {
-        switch (i)
-        {
-          case 0: pixel[j]=GetPixelRed(image,p); break;
-          case 1: pixel[j]=GetPixelGreen(image,p); break;
-          case 2: pixel[j]=GetPixelBlue(image,p); break;
-          case 3: pixel[j]=GetPixelAlpha(image,p); break;
-          case 4: pixel[j]=GetPixelBlack(image,p); break;
-          default: break;
-        }
+        pixel[j++]=p[i];
         p+=GetPixelChannels(image);
-        j++;
       }
       j++;
     }
@@ -1686,29 +1702,20 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 
       q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
         1,exception);
-      if (q == (const Quantum *) NULL)
-        break;
+      if (q == (Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
       j++;
       for (x=0; x < (ssize_t) image->columns; x++)
       {
-        switch (i)
-        {
-          case 0: SetPixelRed(despeckle_image,pixel[j],q); break;
-          case 1: SetPixelGreen(despeckle_image,pixel[j],q); break;
-          case 2: SetPixelBlue(despeckle_image,pixel[j],q); break;
-          case 3: SetPixelAlpha(despeckle_image,pixel[j],q); break;
-          case 4: SetPixelBlack(despeckle_image,pixel[j],q); break;
-          default: break;
-        }
+        SetPixelChannel(despeckle_image,channel,pixel[j++],q);
         q+=GetPixelChannels(despeckle_image);
-        j++;
       }
       sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
       if (sync == MagickFalse)
-        {
-          status=MagickFalse;
-          break;
-        }
+        status=MagickFalse;
       j++;
     }
     if (image->progress_monitor != (MagickProgressMonitor) NULL)
@@ -1717,7 +1724,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
           proceed;
 
         proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
-          number_channels);
+          GetPixelChannels(image));
         if (proceed == MagickFalse)
           status=MagickFalse;
       }
@@ -1750,7 +1757,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 %  The format of the EdgeImage method is:
 %
 %      Image *EdgeImage(const Image *image,const double radius,
-%        ExceptionInfo *exception)
+%        const double sigma,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1758,11 +1765,13 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 %
 %    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 *EdgeImage(const Image *image,const double radius,
-  ExceptionInfo *exception)
+  const double sigma,ExceptionInfo *exception)
 {
   Image
     *edge_image;
@@ -1787,7 +1796,7 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  width=GetOptimalKernelWidth1D(radius,0.5);
+  width=GetOptimalKernelWidth2D(radius,sigma);
   kernel_info=AcquireKernelInfo((const char *) NULL);
   if (kernel_info == (KernelInfo *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -1811,7 +1820,7 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
     }
   }
   kernel_info->values[i/2]=(double) (width*width-1.0);
-  kernel_info->bias=image->bias;
+  kernel_info->bias=image->bias;   /* FUTURE: User bias on a edge image? */
   edge_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(edge_image);
@@ -1906,11 +1915,11 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
     }
     k--;
   }
-  kernel_info->bias=image->bias;
+  kernel_info->bias=image->bias;  /* FUTURE: user bias on an edge image */
   emboss_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   if (emboss_image != (Image *) NULL)
-    (void) EqualizeImage(emboss_image);
+    (void) EqualizeImage(emboss_image,exception);
   return(emboss_image);
 }
 \f
@@ -1933,7 +1942,7 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
 %  The format of the GaussianBlurImage method is:
 %
 %      Image *GaussianBlurImage(const Image *image,onst double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1944,11 +1953,13 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
 %
 %    o sigma: the standard deviation of the Gaussian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
   Image
     *blur_image;
@@ -1980,6 +1991,7 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
   kernel_info->width=width;
   kernel_info->height=width;
+  kernel_info->bias=bias;  /* FUTURE: user bias on Gaussian Blur! non-sense */
   kernel_info->signature=MagickSignature;
   kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
     kernel_info->width*sizeof(*kernel_info->values));
@@ -1999,7 +2011,6 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
       i++;
     }
   }
-  kernel_info->bias=image->bias;
   blur_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(blur_image);
@@ -2027,7 +2038,8 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
 %  The format of the MotionBlurImage method is:
 %
 %    Image *MotionBlurImage(const Image *image,const double radius,
-%      const double sigma,const double angle,ExceptionInfo *exception)
+%      const double sigma,const double angle,const double bias,
+%      ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2040,6 +2052,8 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
 %
 %    o angle: Apply the effect along this angle.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -2072,8 +2086,8 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma)
   return(kernel);
 }
 
-MagickExport Image *MotionBlurImage(const Image *image,
-  const double radius,const double sigma,const double angle,
+MagickExport Image *MotionBlurImage(const Image *image,const double radius,
+  const double sigma,const double angle,const double bias,
   ExceptionInfo *exception)
 {
   CacheView
@@ -2092,9 +2106,6 @@ MagickExport Image *MotionBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   OffsetInfo
     *offset;
 
@@ -2125,18 +2136,17 @@ MagickExport Image *MotionBlurImage(const Image *image,
       kernel=(double *) RelinquishMagickMemory(kernel);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
     }
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     {
       kernel=(double *) RelinquishMagickMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
       return((Image *) NULL);
     }
-  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
       kernel=(double *) RelinquishMagickMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
-      InheritException(exception,&blur_image->exception);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
@@ -2152,7 +2162,6 @@ MagickExport Image *MotionBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
@@ -2160,6 +2169,9 @@ MagickExport Image *MotionBlurImage(const Image *image,
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
+    register const Quantum
+      *restrict p;
+
     register Quantum
       *restrict q;
 
@@ -2168,100 +2180,92 @@ MagickExport Image *MotionBlurImage(const Image *image,
 
     if (status == MagickFalse)
       continue;
+    p=GetCacheViewVirtualPixels(blur_view,0,y,image->columns,1,exception);
     q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        qixel;
+      register ssize_t
+        i;
 
-      PixelPacket
-        pixel;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register double
-        *restrict k;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      k=kernel;
-      qixel=bias;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
+        register const Quantum
+          *restrict r;
+
+        register double
+          *restrict k;
+
+        register ssize_t
+          j;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
-              offset[i].y,&pixel,exception);
-            qixel.red+=(*k)*pixel.red;
-            qixel.green+=(*k)*pixel.green;
-            qixel.blue+=(*k)*pixel.blue;
-            qixel.alpha+=(*k)*pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=(*k)*pixel.black;
-            k++;
+            SetPixelChannel(blur_image,channel,p[i],q);
+            continue;
           }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(qixel.alpha),q);
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
-
-          alpha=0.0;
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
+        k=kernel;
+        pixel=bias;
+        if ((blur_traits & BlendPixelTrait) == 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
-              offset[i].y,&pixel,exception);
-            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
-            qixel.red+=(*k)*alpha*pixel.red;
-            qixel.green+=(*k)*alpha*pixel.green;
-            qixel.blue+=(*k)*alpha*pixel.blue;
-            qixel.alpha+=(*k)*pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=(*k)*alpha*pixel.black;
-            gamma+=(*k)*alpha;
-            k++;
+            for (j=0; j < (ssize_t) width; j++)
+            {
+              r=GetCacheViewVirtualPixels(image_view,x+offset[j].x,y+
+                offset[j].y,1,1,exception);
+              if (r == (const Quantum *) NULL)
+                {
+                  status=MagickFalse;
+                  continue;
+                }
+              pixel+=(*k)*r[i];
+              k++;
+            }
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(gamma*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(gamma*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(gamma*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(gamma*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(qixel.alpha),q);
+        alpha=0.0;
+        gamma=0.0;
+        for (j=0; j < (ssize_t) width; j++)
+        {
+          r=GetCacheViewVirtualPixels(image_view,x+offset[j].x,y+offset[j].y,1,
+            1,exception);
+          if (r == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              continue;
+            }
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,r));
+          pixel+=(*k)*alpha*r[i];
+          gamma+=(*k)*alpha;
+          k++;
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
+      p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
@@ -2397,10 +2401,11 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       break;
     (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
       (void *) NULL);
-    (void) SetImageProperty(thumbnail,"label",DefaultTileLabel);
+    (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
     if (i == (NumberTiles/2))
       {
-        (void) QueryColorDatabase("#dfdfdf",&thumbnail->matte_color,exception);
+        (void) QueryColorCompliance("#dfdfdf",AllCompliance,
+          &thumbnail->matte_color,exception);
         AppendImageToList(&images,thumbnail);
         continue;
       }
@@ -2437,7 +2442,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",
           2.0*percentage);
-        (void) ModulateImage(preview_image,factor);
+        (void) ModulateImage(preview_image,factor,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
         break;
       }
@@ -2448,7 +2453,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",
           2.0*percentage);
-        (void) ModulateImage(preview_image,factor);
+        (void) ModulateImage(preview_image,factor,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
         break;
       }
@@ -2458,7 +2463,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         (void) FormatLocaleString(factor,MaxTextExtent,"%g",2.0*percentage);
-        (void) ModulateImage(preview_image,factor);
+        (void) ModulateImage(preview_image,factor,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
         break;
       }
@@ -2469,7 +2474,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         gamma+=0.4f;
-        (void) GammaImage(preview_image,gamma);
+        (void) GammaImage(preview_image,gamma,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"gamma %g",gamma);
         break;
       }
@@ -2478,7 +2483,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         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) ContrastImage(preview_image,MagickTrue,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"contrast (%.20g)",
           (double) i+1);
         break;
@@ -2489,7 +2494,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         for (x=0; x < i; x++)
-          (void) ContrastImage(preview_image,MagickFalse);
+          (void) ContrastImage(preview_image,MagickFalse,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"+contrast (%.20g)",
           (double) i+1);
         break;
@@ -2502,7 +2507,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         colors<<=1;
         quantize_info.number_colors=colors;
         quantize_info.colorspace=GRAYColorspace;
-        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) QuantizeImage(&quantize_info,preview_image,exception);
         (void) FormatLocaleString(label,MaxTextExtent,
           "-colorspace gray -colors %.20g",(double) colors);
         break;
@@ -2514,7 +2519,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         colors<<=1;
         quantize_info.number_colors=colors;
-        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) QuantizeImage(&quantize_info,preview_image,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"colors %.20g",(double)
           colors);
         break;
@@ -2590,14 +2595,17 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       }
       case SharpenPreview:
       {
-        preview_image=SharpenImage(thumbnail,radius,sigma,exception);
+        /* FUTURE: user bias on sharpen! This is non-sensical! */
+        preview_image=SharpenImage(thumbnail,radius,sigma,image->bias,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",
           radius,sigma);
         break;
       }
       case BlurPreview:
       {
-        preview_image=BlurImage(thumbnail,radius,sigma,exception);
+        /* FUTURE: user bias on blur! This is non-sensical! */
+        preview_image=BlurImage(thumbnail,radius,sigma,image->bias,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius,
           sigma);
         break;
@@ -2607,21 +2615,22 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         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) BilevelImage(thumbnail,(double) (percentage*((MagickRealType)
+          QuantumRange+1.0))/100.0,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",
           (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
         break;
       }
       case EdgeDetectPreview:
       {
-        preview_image=EdgeImage(thumbnail,radius,exception);
+        preview_image=EdgeImage(thumbnail,radius,sigma,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"edge %g",radius);
         break;
       }
       case SpreadPreview:
       {
-        preview_image=SpreadImage(thumbnail,radius,exception);
+        preview_image=SpreadImage(thumbnail,radius,thumbnail->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"spread %g",
           radius+0.5);
         break;
@@ -2632,7 +2641,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         (void) SolarizeImage(preview_image,(double) QuantumRange*
-          percentage/100.0);
+          percentage/100.0,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
           (QuantumRange*percentage)/100.0);
         break;
@@ -2655,7 +2664,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         geometry.height=(size_t) (2*i+2);
         geometry.x=i/2;
         geometry.y=i/2;
-        (void) RaiseImage(preview_image,&geometry,MagickTrue);
+        (void) RaiseImage(preview_image,&geometry,MagickTrue,exception);
         (void) FormatLocaleString(label,MaxTextExtent,
           "raise %.20gx%.20g%+.20g%+.20g",(double) geometry.width,(double)
           geometry.height,(double) geometry.x,(double) geometry.y);
@@ -2668,14 +2677,15 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         threshold+=0.4f;
         (void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold,
-          threshold);
+          threshold,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
           threshold,threshold);
         break;
       }
       case SwirlPreview:
       {
-        preview_image=SwirlImage(thumbnail,degrees,exception);
+        preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"swirl %g",degrees);
         degrees+=45.0;
         break;
@@ -2683,28 +2693,33 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       case ImplodePreview:
       {
         degrees+=0.1f;
-        preview_image=ImplodeImage(thumbnail,degrees,exception);
+        preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"implode %g",degrees);
         break;
       }
       case WavePreview:
       {
         degrees+=5.0f;
-        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
+        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
+          image->interpolate,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",
           0.5*degrees,2.0*degrees);
         break;
       }
       case OilPaintPreview:
       {
-        preview_image=OilPaintImage(thumbnail,(double) radius,exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"paint %g",radius);
+        preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
+          exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
+          radius,sigma);
         break;
       }
       case CharcoalDrawingPreview:
       {
+        /* FUTURE: user bias on charcoal! This is non-sensical! */
         preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
-          exception);
+          image->bias,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
           radius,sigma);
         break;
@@ -2731,7 +2746,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           file=close(file)-1;
         (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
           "jpeg:%s",filename);
-        status=WriteImage(preview_info,preview_image);
+        status=WriteImage(preview_info,preview_image,exception);
         if (status != MagickFalse)
           {
             Image
@@ -2769,7 +2784,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
     if (preview_image == (Image *) NULL)
       break;
     (void) DeleteImageProperty(preview_image,"label");
-    (void) SetImageProperty(preview_image,"label",label);
+    (void) SetImageProperty(preview_image,"label",label,exception);
     AppendImageToList(&images,preview_image);
     proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
       NumberTiles);
@@ -2828,7 +2843,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
 %  The format of the RadialBlurImage method is:
 %
 %    Image *RadialBlurImage(const Image *image,const double angle,
-%      ExceptionInfo *exception)
+%      const double blur,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2836,11 +2851,13 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
 %
 %    o angle: the angle of the radial blur.
 %
+%    o blur: the blur.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *RadialBlurImage(const Image *image,
-  const double angle,ExceptionInfo *exception)
+  const double angle,const double bias,ExceptionInfo *exception)
 {
   CacheView
     *blur_view,
@@ -2855,9 +2872,6 @@ MagickExport Image *RadialBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   MagickRealType
     blur_radius,
     *cos_theta,
@@ -2886,12 +2900,11 @@ MagickExport Image *RadialBlurImage(const Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&blur_image->exception);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
@@ -2921,14 +2934,16 @@ MagickExport Image *RadialBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
 #endif
-  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
+    register const Quantum
+      *restrict p;
+
     register Quantum
       *restrict q;
 
@@ -2937,25 +2952,19 @@ MagickExport Image *RadialBlurImage(const Image *image,
 
     if (status == MagickFalse)
       continue;
+    p=GetCacheViewVirtualPixels(blur_view,0,y,image->columns,1,exception);
     q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        qixel;
-
       MagickRealType
-        normalize,
         radius;
 
-      PixelPacket
-        pixel;
-
       PointInfo
         center;
 
@@ -2979,87 +2988,76 @@ MagickExport Image *RadialBlurImage(const Image *image,
             if (step >= n)
               step=n-1;
         }
-      normalize=0.0;
-      qixel=bias;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          blur_traits,
+          traits;
+
+        register const Quantum
+          *restrict r;
+
+        register ssize_t
+          j;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
-              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
-              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
-              cos_theta[i]+0.5),&pixel,exception);
-            qixel.red+=pixel.red;
-            qixel.green+=pixel.green;
-            qixel.blue+=pixel.blue;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=pixel.black;
-            qixel.alpha+=pixel.alpha;
-            normalize+=1.0;
+            SetPixelChannel(blur_image,channel,p[i],q);
+            continue;
           }
-          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
-            normalize);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(normalize*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(normalize*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(normalize*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(normalize*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(normalize*qixel.alpha),q);
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
-
-          alpha=1.0;
-          gamma=0.0;
-          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+        gamma=0.0;
+        pixel=bias;
+        if ((blur_traits & BlendPixelTrait) == 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
-              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
-              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
-              cos_theta[i]+0.5),&pixel,exception);
-            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
-            qixel.red+=alpha*pixel.red;
-            qixel.green+=alpha*pixel.green;
-            qixel.blue+=alpha*pixel.blue;
-            qixel.alpha+=pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=alpha*pixel.black;
-            gamma+=alpha;
-            normalize+=1.0;
+            for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
+            {
+              r=GetCacheViewVirtualPixels(image_view, (ssize_t) (blur_center.x+
+                center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
+                (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
+                1,1,exception);
+              if (r == (const Quantum *) NULL)
+                {
+                  status=MagickFalse;
+                  continue;
+                }
+              pixel+=r[i];
+              gamma++;
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
-            normalize);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(gamma*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(gamma*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(gamma*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(gamma*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(normalize*qixel.alpha),q);
+        for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
+        {
+          r=GetCacheViewVirtualPixels(image_view, (ssize_t) (blur_center.x+
+            center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
+            (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
+            1,1,exception);
+          if (r == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              continue;
+            }
+          pixel+=GetPixelAlpha(image,r)*r[i];
+          gamma+=GetPixelAlpha(image,r);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
+      p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
@@ -3104,7 +3102,8 @@ MagickExport Image *RadialBlurImage(const Image *image,
 %  The format of the SelectiveBlurImage method is:
 %
 %      Image *SelectiveBlurImage(const Image *image,const double radius,
-%        const double sigma,const double threshold,ExceptionInfo *exception)
+%        const double sigma,const double threshold,const double bias,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3118,12 +3117,14 @@ MagickExport Image *RadialBlurImage(const Image *image,
 %    o threshold: only pixels within this contrast threshold are included
 %      in the blur operation.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *SelectiveBlurImage(const Image *image,
   const double radius,const double sigma,const double threshold,
-  ExceptionInfo *exception)
+  const double bias,ExceptionInfo *exception)
 {
 #define SelectiveBlurImageTag  "SelectiveBlur/Image"
 
@@ -3143,9 +3144,6 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -3153,6 +3151,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
     width;
 
   ssize_t
+    center,
     j,
     u,
     v,
@@ -3211,12 +3210,11 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
       }
       message=DestroyString(message);
     }
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&blur_image->exception);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
@@ -3225,8 +3223,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
+  center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*(width/2L)+
+    GetPixelChannels(image)*(width/2L));
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
@@ -3240,9 +3238,6 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
     MagickBooleanType
       sync;
 
-    MagickRealType
-      gamma;
-
     register const Quantum
       *restrict p;
 
@@ -3265,165 +3260,103 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          intensity,
+          pixel;
 
-      register ssize_t
-        u;
+        PixelChannel
+          channel;
 
-      ssize_t
-        j,
-        v;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      gamma=0.0;
-      j=0;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (v=0; v < (ssize_t) width; v++)
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            for (u=0; u < (ssize_t) width; u++)
-            {
-              contrast=GetPixelIntensity(image,p+(u+j)*GetPixelChannels(image))-
-                (double) GetPixelIntensity(blur_image,q);
-              if (fabs(contrast) < threshold)
-                {
-                  pixel.red+=(*k)*
-                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.green+=(*k)*
-                    GetPixelGreen(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.blue+=(*k)*
-                    GetPixelBlue(image,p+(u+j)*GetPixelChannels(image));
-                  if (image->colorspace == CMYKColorspace)
-                    pixel.black+=(*k)*
-                      GetPixelBlack(image,p+(u+j)*GetPixelChannels(image));
-                  gamma+=(*k);
-                  k++;
-                }
-            }
-            j+=(ssize_t) (image->columns+width);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          if (gamma != 0.0)
-            {
-              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-              if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-              if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-              if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-              if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-                  (image->colorspace == CMYKColorspace))
-                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-            }
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixel=bias;
+        pixels=p;
+        intensity=(MagickRealType) GetPixelIntensity(image,p+center);
+        gamma=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            for (v=0; v < (ssize_t) width; v++)
             {
-              gamma=0.0;
-              j=0;
-              for (v=0; v < (ssize_t) width; v++)
+              for (u=0; u < (ssize_t) width; u++)
               {
-                for (u=0; u < (ssize_t) width; u++)
-                {
-                  contrast=GetPixelIntensity(image,p+(u+j)*
-                    GetPixelChannels(image))-(double)
-                    GetPixelIntensity(blur_image,q);
-                  if (fabs(contrast) < threshold)
-                    {
-                      pixel.alpha+=(*k)*
-                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
-                      gamma+=(*k);
-                      k++;
-                    }
-                }
-                j+=(ssize_t) (image->columns+width);
+                contrast=GetPixelIntensity(image,pixels)-intensity;
+                if (fabs(contrast) < threshold)
+                  {
+                    pixel+=(*k)*pixels[i];
+                    gamma+=(*k);
+                  }
+                k++;
+                pixels+=GetPixelChannels(image);
               }
-              if (gamma != 0.0)
-                {
-                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
-                    gamma);
-                  SetPixelAlpha(blur_image,ClampToQuantum(gamma*pixel.alpha),q);
-                }
+              pixels+=image->columns*GetPixelChannels(image);
             }
-        }
-      else
+            if (fabs((double) gamma) < MagickEpsilon)
+              {
+                SetPixelChannel(blur_image,channel,p[center+i],q);
+                continue;
+              }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        for (v=0; v < (ssize_t) width; v++)
         {
-          MagickRealType
-            alpha;
-
-          for (v=0; v < (ssize_t) width; v++)
+          for (u=0; u < (ssize_t) width; u++)
           {
-            for (u=0; u < (ssize_t) width; u++)
-            {
-              contrast=GetPixelIntensity(image,p+(u+j)*
-                GetPixelChannels(image))-(double)
-                GetPixelIntensity(blur_image,q);
-              if (fabs(contrast) < threshold)
-                {
-                  alpha=(MagickRealType) (QuantumScale*
-                    GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image)));
-                  pixel.red+=(*k)*alpha*
-                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.green+=(*k)*alpha*GetPixelGreen(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  pixel.blue+=(*k)*alpha*GetPixelBlue(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  pixel.alpha+=(*k)*GetPixelAlpha(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  if (image->colorspace == CMYKColorspace)
-                    pixel.black+=(*k)*GetPixelBlack(image,p+(u+j)*
-                      GetPixelChannels(image));
-                  gamma+=(*k)*alpha;
-                  k++;
-                }
-            }
-            j+=(ssize_t) (image->columns+width);
-          }
-          if (gamma != 0.0)
-            {
-              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-              if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-              if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-              if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-              if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-                  (image->colorspace == CMYKColorspace))
-                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-            }
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              gamma=0.0;
-              j=0;
-              for (v=0; v < (ssize_t) width; v++)
+            contrast=GetPixelIntensity(image,pixels)-intensity;
+            if (fabs(contrast) < threshold)
               {
-                for (u=0; u < (ssize_t) width; u++)
-                {
-                  contrast=GetPixelIntensity(image,p+(u+j)*
-                    GetPixelChannels(image))-(double)
-                    GetPixelIntensity(blur_image,q);
-                  if (fabs(contrast) < threshold)
-                    {
-                      pixel.alpha+=(*k)*
-                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
-                      gamma+=(*k);
-                      k++;
-                    }
-                }
-                j+=(ssize_t) (image->columns+width);
+                alpha=(MagickRealType) (QuantumScale*
+                  GetPixelAlpha(image,pixels));
+                pixel+=(*k)*alpha*pixels[i];
+                gamma+=(*k)*alpha;
               }
-              if (gamma != 0.0)
-                {
-                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
-                    gamma);
-                  SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-                }
-            }
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
+          pixels+=image->columns*GetPixelChannels(image);
         }
+        if (fabs((double) gamma) < MagickEpsilon)
+          {
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
+          }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
@@ -3521,9 +3454,8 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
   shade_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (shade_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(shade_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&shade_image->exception);
       shade_image=DestroyImage(shade_image);
       return((Image *) NULL);
     }
@@ -3556,10 +3488,10 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
       normal;
 
     register const Quantum
+      *restrict center,
       *restrict p,
-      *restrict s0,
-      *restrict s1,
-      *restrict s2;
+      *restrict post,
+      *restrict pre;
 
     register Quantum
       *restrict q;
@@ -3581,26 +3513,28 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
       Shade this row of pixels.
     */
     normal.z=2.0*(double) QuantumRange;  /* constant Z of surface normal */
-    s0=p+GetPixelChannels(image);
-    s1=s0+(image->columns+2)*GetPixelChannels(image);
-    s2=s1+(image->columns+2)*GetPixelChannels(image);
+    pre=p+GetPixelChannels(image);
+    center=pre+(image->columns+2)*GetPixelChannels(image);
+    post=center+(image->columns+2)*GetPixelChannels(image);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
+      register ssize_t
+        i;
+
       /*
         Determine the surface normal and compute shading.
       */
-      normal.x=(double) (GetPixelIntensity(image,s0-GetPixelChannels(image))+
-        GetPixelIntensity(image,s1-GetPixelChannels(image))+
-        GetPixelIntensity(image,s2-GetPixelChannels(image))-
-        GetPixelIntensity(image,s0+GetPixelChannels(image))-
-        GetPixelIntensity(image,s1+GetPixelChannels(image))-
-        GetPixelIntensity(image,s2+GetPixelChannels(image)));
-      normal.y=(double) (GetPixelIntensity(image,s2-GetPixelChannels(image))+
-        GetPixelIntensity(image,s2)+
-        GetPixelIntensity(image,s2+GetPixelChannels(image))-
-        GetPixelIntensity(image,s0-GetPixelChannels(image))-
-        GetPixelIntensity(image,s0)-
-        GetPixelIntensity(image,s0+GetPixelChannels(image)));
+      normal.x=(double) (GetPixelIntensity(image,pre-GetPixelChannels(image))+
+        GetPixelIntensity(image,center-GetPixelChannels(image))+
+        GetPixelIntensity(image,post-GetPixelChannels(image))-
+        GetPixelIntensity(image,pre+GetPixelChannels(image))-
+        GetPixelIntensity(image,center+GetPixelChannels(image))-
+        GetPixelIntensity(image,post+GetPixelChannels(image)));
+      normal.y=(double) (GetPixelIntensity(image,post-GetPixelChannels(image))+
+        GetPixelIntensity(image,post)+GetPixelIntensity(image,post+
+        GetPixelChannels(image))-GetPixelIntensity(image,pre-
+        GetPixelChannels(image))-GetPixelIntensity(image,pre)-
+        GetPixelIntensity(image,pre+GetPixelChannels(image)));
       if ((normal.x == 0.0) && (normal.y == 0.0))
         shade=light.z;
       else
@@ -3612,28 +3546,40 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
               normal_distance=
                 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
               if (normal_distance > (MagickEpsilon*MagickEpsilon))
-                shade=distance/sqrt((double) normal_distance);
-            }
-        }
-      if (gray != MagickFalse)
-        {
-          SetPixelRed(shade_image,ClampToQuantum(shade),q);
-          SetPixelGreen(shade_image,ClampToQuantum(shade),q);
-          SetPixelBlue(shade_image,ClampToQuantum(shade),q);
-        }
-      else
-        {
-          SetPixelRed(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelRed(image,s1)),q);
-          SetPixelGreen(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelGreen(image,s1)),q);
-          SetPixelBlue(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelBlue(image,s1)),q);
+                shade=distance/sqrt((double) normal_distance);
+            }
         }
-      SetPixelAlpha(shade_image,GetPixelAlpha(image,s1),q);
-      s0+=GetPixelChannels(image);
-      s1+=GetPixelChannels(image);
-      s2+=GetPixelChannels(image);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          shade_traits,
+          traits;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        shade_traits=GetPixelChannelMapTraits(shade_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (shade_traits == UndefinedPixelTrait))
+          continue;
+        if ((shade_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(shade_image,channel,center[i],q);
+            continue;
+          }
+        if (gray != MagickFalse)
+          {
+            SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
+            continue;
+          }
+        SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
+          center[i]),q);
+      }
+      pre+=GetPixelChannels(image);
+      center+=GetPixelChannels(image);
+      post+=GetPixelChannels(image);
       q+=GetPixelChannels(shade_image);
     }
     if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
@@ -3682,7 +3628,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
 %  The format of the SharpenImage method is:
 %
 %    Image *SharpenImage(const Image *image,const double radius,
-%      const double sigma,ExceptionInfo *exception)
+%      const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3693,11 +3639,13 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *SharpenImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
   double
     normalize;
@@ -3732,6 +3680,7 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
   kernel_info->width=width;
   kernel_info->height=width;
+  kernel_info->bias=bias;   /* FUTURE: user bias - non-sensical! */
   kernel_info->signature=MagickSignature;
   kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
     kernel_info->width*sizeof(*kernel_info->values));
@@ -3754,7 +3703,6 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
     }
   }
   kernel_info->values[i/2]=(double) ((-2.0)*normalize);
-  kernel_info->bias=image->bias;
   sharp_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(sharp_image);
@@ -3777,19 +3725,21 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
 %  The format of the SpreadImage method is:
 %
 %      Image *SpreadImage(const Image *image,const double radius,
-%        ExceptionInfo *exception)
+%        const PixelInterpolateMethod method,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 radius:  choose a random pixel in a neighborhood of this extent.
+%
+%    o method:  the pixel interpolation method.
 %
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *SpreadImage(const Image *image,const double radius,
-  ExceptionInfo *exception)
+  const PixelInterpolateMethod method,ExceptionInfo *exception)
 {
 #define SpreadImageTag  "Spread/Image"
 
@@ -3806,9 +3756,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   RandomInfo
     **restrict random_info;
 
@@ -3831,9 +3778,8 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
     exception);
   if (spread_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&spread_image->exception);
       spread_image=DestroyImage(spread_image);
       return((Image *) NULL);
     }
@@ -3842,7 +3788,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(spread_image,&bias);
   width=GetOptimalKernelWidth1D(radius,0.5);
   random_info=AcquireRandomInfoThreadSet();
   image_view=AcquireCacheView(image);
@@ -3850,13 +3795,13 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
 #endif
-  for (y=0; y < (ssize_t) spread_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
     const int
       id = GetOpenMPThreadId();
 
-    PixelInfo
-      pixel;
+    register const Quantum
+      *restrict p;
 
     register Quantum
       *restrict q;
@@ -3866,21 +3811,23 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 
     if (status == MagickFalse)
       continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
     q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    pixel=bias;
-    for (x=0; x < (ssize_t) spread_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      (void) InterpolatePixelInfo(image,image_view,
-        UndefinedInterpolatePixel,(double) x+width*(GetPseudoRandomValue(
-        random_info[id])-0.5),(double) y+width*(GetPseudoRandomValue(
-        random_info[id])-0.5),&pixel,exception);
-      SetPixelPixelInfo(spread_image,&pixel,q);
+      PointInfo
+        point;
+
+      point.x=GetPseudoRandomValue(random_info[id]);
+      point.y=GetPseudoRandomValue(random_info[id]);
+      status=InterpolatePixelChannels(image,image_view,spread_image,method,
+        (double) x+width*point.x-0.5,(double) y+width*point.y-0.5,q,exception);
       q+=GetPixelChannels(spread_image);
     }
     if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
@@ -3937,22 +3884,20 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 %
 */
 
-#define ListChannels  5
-
-typedef struct _ListNode
+typedef struct _SkipNode
 {
   size_t
     next[9],
     count,
     signature;
-} ListNode;
+} SkipNode;
 
 typedef struct _SkipList
 {
   ssize_t
     level;
 
-  ListNode
+  SkipNode
     *nodes;
 } SkipList;
 
@@ -3960,24 +3905,22 @@ typedef struct _PixelList
 {
   size_t
     length,
-    seed,
-    signature;
+    seed;
 
   SkipList
-    lists[ListChannels];
+    skip_list;
+
+  size_t
+    signature;
 } PixelList;
 
 static PixelList *DestroyPixelList(PixelList *pixel_list)
 {
-  register ssize_t
-    i;
-
   if (pixel_list == (PixelList *) NULL)
     return((PixelList *) NULL);
-  for (i=0; i < ListChannels; i++)
-    if (pixel_list->lists[i].nodes != (ListNode *) NULL)
-      pixel_list->lists[i].nodes=(ListNode *) RelinquishMagickMemory(
-        pixel_list->lists[i].nodes);
+  if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
+    pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
+      pixel_list->skip_list.nodes);
   pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
   return(pixel_list);
 }
@@ -4000,23 +3943,17 @@ static PixelList *AcquirePixelList(const size_t width,const size_t height)
   PixelList
     *pixel_list;
 
-  register ssize_t
-    i;
-
   pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
   if (pixel_list == (PixelList *) NULL)
     return(pixel_list);
   (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
   pixel_list->length=width*height;
-  for (i=0; i < ListChannels; i++)
-  {
-    pixel_list->lists[i].nodes=(ListNode *) AcquireQuantumMemory(65537UL,
-      sizeof(*pixel_list->lists[i].nodes));
-    if (pixel_list->lists[i].nodes == (ListNode *) NULL)
-      return(DestroyPixelList(pixel_list));
-    (void) ResetMagickMemory(pixel_list->lists[i].nodes,0,65537UL*
-      sizeof(*pixel_list->lists[i].nodes));
-  }
+  pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
+    sizeof(*pixel_list->skip_list.nodes));
+  if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
+    return(DestroyPixelList(pixel_list));
+  (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
+    sizeof(*pixel_list->skip_list.nodes));
   pixel_list->signature=MagickSignature;
   return(pixel_list);
 }
@@ -4048,11 +3985,10 @@ static PixelList **AcquirePixelListThreadSet(const size_t width,
   return(pixel_list);
 }
 
-static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
-  const size_t color)
+static void AddNodePixelList(PixelList *pixel_list,const size_t color)
 {
   register SkipList
-    *list;
+    *p;
 
   register ssize_t
     level;
@@ -4064,17 +4000,17 @@ static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
   /*
     Initialize the node.
   */
-  list=pixel_list->lists+channel;
-  list->nodes[color].signature=pixel_list->signature;
-  list->nodes[color].count=1;
+  p=(&pixel_list->skip_list);
+  p->nodes[color].signature=pixel_list->signature;
+  p->nodes[color].count=1;
   /*
     Determine where it belongs in the list.
   */
   search=65536UL;
-  for (level=list->level; level >= 0; level--)
+  for (level=p->level; level >= 0; level--)
   {
-    while (list->nodes[search].next[level] < color)
-      search=list->nodes[search].next[level];
+    while (p->nodes[search].next[level] < color)
+      search=p->nodes[search].next[level];
     update[level]=search;
   }
   /*
@@ -4088,36 +4024,30 @@ static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
   }
   if (level > 8)
     level=8;
-  if (level > (list->level+2))
-    level=list->level+2;
+  if (level > (p->level+2))
+    level=p->level+2;
   /*
     If we're raising the list's level, link back to the root node.
   */
-  while (level > list->level)
+  while (level > p->level)
   {
-    list->level++;
-    update[list->level]=65536UL;
+    p->level++;
+    update[p->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;
+    p->nodes[color].next[level]=p->nodes[update[level]].next[level];
+    p->nodes[update[level]].next[level]=color;
   } while (level-- > 0);
 }
 
-static PixelInfo GetMaximumPixelList(PixelList *pixel_list)
+static Quantum GetMaximumPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color,
@@ -4126,49 +4056,30 @@ static PixelInfo GetMaximumPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[ListChannels];
-
   /*
     Find the maximum value for each of the color.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  count=0;
+  maximum=p->nodes[color].next[0];
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    maximum=list->nodes[color].next[0];
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (color > maximum)
-        maximum=color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) maximum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
+    color=p->nodes[color].next[0];
+    if (color > maximum)
+      maximum=color;
+    count+=p->nodes[color].count;
+  } while (count < (ssize_t) pixel_list->length);
+  return(ScaleShortToQuantum((unsigned short) maximum));
 }
 
-static PixelInfo GetMeanPixelList(PixelList *pixel_list)
+static Quantum GetMeanPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   MagickRealType
     sum;
 
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color;
@@ -4176,46 +4087,27 @@ static PixelInfo GetMeanPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[ListChannels];
-
   /*
     Find the mean value for each of the color.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  count=0;
+  sum=0.0;
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    sum=0.0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      sum+=(MagickRealType) list->nodes[color].count*color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    sum/=pixel_list->length;
-    channels[channel]=(unsigned short) sum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
+    color=p->nodes[color].next[0];
+    sum+=(MagickRealType) p->nodes[color].count*color;
+    count+=p->nodes[color].count;
+  } while (count < (ssize_t) pixel_list->length);
+  sum/=pixel_list->length;
+  return(ScaleShortToQuantum((unsigned short) sum));
 }
 
-static PixelInfo GetMedianPixelList(PixelList *pixel_list)
+static Quantum GetMedianPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color;
@@ -4223,43 +4115,24 @@ static PixelInfo GetMedianPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[ListChannels];
-
   /*
     Find the median value for each of the color.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  count=0;
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      count+=list->nodes[color].count;
-    } while (count <= (ssize_t) (pixel_list->length >> 1));
-    channels[channel]=(unsigned short) color;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
+    color=p->nodes[color].next[0];
+    count+=p->nodes[color].count;
+  } while (count <= (ssize_t) (pixel_list->length >> 1));
+  return(ScaleShortToQuantum((unsigned short) color));
 }
 
-static PixelInfo GetMinimumPixelList(PixelList *pixel_list)
+static Quantum GetMinimumPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color,
@@ -4268,46 +4141,27 @@ static PixelInfo GetMinimumPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[ListChannels];
-
   /*
     Find the minimum value for each of the color.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  count=0;
+  color=65536UL;
+  minimum=p->nodes[color].next[0];
+  do
   {
-    list=pixel_list->lists+channel;
-    count=0;
-    color=65536UL;
-    minimum=list->nodes[color].next[0];
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (color < minimum)
-        minimum=color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) minimum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
+    color=p->nodes[color].next[0];
+    if (color < minimum)
+      minimum=color;
+    count+=p->nodes[color].count;
+  } while (count < (ssize_t) pixel_list->length);
+  return(ScaleShortToQuantum((unsigned short) minimum));
 }
 
-static PixelInfo GetModePixelList(PixelList *pixel_list)
+static Quantum GetModePixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color,
@@ -4317,50 +4171,31 @@ static PixelInfo GetModePixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[5];
-
   /*
     Make each pixel the 'predominant color' of the specified neighborhood.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  mode=color;
+  max_count=p->nodes[mode].count;
+  count=0;
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    mode=color;
-    max_count=list->nodes[mode].count;
-    count=0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (list->nodes[color].count > max_count)
-        {
-          mode=color;
-          max_count=list->nodes[mode].count;
-        }
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) mode;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
+    color=p->nodes[color].next[0];
+    if (p->nodes[color].count > max_count)
+      {
+        mode=color;
+        max_count=p->nodes[mode].count;
+      }
+    count+=p->nodes[color].count;
+  } while (count < (ssize_t) pixel_list->length);
+  return(ScaleShortToQuantum((unsigned short) mode));
 }
 
-static PixelInfo GetNonpeakPixelList(PixelList *pixel_list)
+static Quantum GetNonpeakPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color,
@@ -4370,55 +4205,36 @@ static PixelInfo GetNonpeakPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[5];
-
   /*
     Finds the non peak value for each of the colors.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  next=p->nodes[color].next[0];
+  count=0;
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    next=list->nodes[color].next[0];
-    count=0;
-    do
-    {
-      previous=color;
-      color=next;
-      next=list->nodes[color].next[0];
-      count+=list->nodes[color].count;
-    } while (count <= (ssize_t) (pixel_list->length >> 1));
-    if ((previous == 65536UL) && (next != 65536UL))
-      color=next;
-    else
-      if ((previous != 65536UL) && (next == 65536UL))
-        color=previous;
-    channels[channel]=(unsigned short) color;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
+    previous=color;
+    color=next;
+    next=p->nodes[color].next[0];
+    count+=p->nodes[color].count;
+  } while (count <= (ssize_t) (pixel_list->length >> 1));
+  if ((previous == 65536UL) && (next != 65536UL))
+    color=next;
+  else
+    if ((previous != 65536UL) && (next == 65536UL))
+      color=previous;
+  return(ScaleShortToQuantum((unsigned short) color));
 }
 
-static PixelInfo GetStandardDeviationPixelList(PixelList *pixel_list)
+static Quantum GetStandardDeviationPixelList(PixelList *pixel_list)
 {
-  PixelInfo
-    pixel;
-
   MagickRealType
     sum,
     sum_squared;
 
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   size_t
     color;
@@ -4426,44 +4242,31 @@ static PixelInfo GetStandardDeviationPixelList(PixelList *pixel_list)
   ssize_t
     count;
 
-  unsigned short
-    channels[ListChannels];
-
   /*
     Find the standard-deviation value for each of the color.
   */
-  for (channel=0; channel < 5; channel++)
+  p=(&pixel_list->skip_list);
+  color=65536L;
+  count=0;
+  sum=0.0;
+  sum_squared=0.0;
+  do
   {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    sum=0.0;
-    sum_squared=0.0;
-    do
-    {
-      register ssize_t
-        i;
-
-      color=list->nodes[color].next[0];
-      sum+=(MagickRealType) list->nodes[color].count*color;
-      for (i=0; i < (ssize_t) list->nodes[color].count; i++)
-        sum_squared+=((MagickRealType) color)*((MagickRealType) color);
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    sum/=pixel_list->length;
-    sum_squared/=pixel_list->length;
-    channels[channel]=(unsigned short) sqrt(sum_squared-(sum*sum));
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
+    register ssize_t
+      i;
+
+    color=p->nodes[color].next[0];
+    sum+=(MagickRealType) p->nodes[color].count*color;
+    for (i=0; i < (ssize_t) p->nodes[color].count; i++)
+      sum_squared+=((MagickRealType) color)*((MagickRealType) color);
+    count+=p->nodes[color].count;
+  } while (count < (ssize_t) pixel_list->length);
+  sum/=pixel_list->length;
+  sum_squared/=pixel_list->length;
+  return(ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum))));
 }
 
-static inline void InsertPixelList(const Image *image,const Quantum *pixel,
+static inline void InsertPixelList(const Image *image,const Quantum pixel,
   PixelList *pixel_list)
 {
   size_t
@@ -4472,37 +4275,14 @@ static inline void InsertPixelList(const Image *image,const Quantum *pixel,
   unsigned short
     index;
 
-  index=ScaleQuantumToShort(GetPixelRed(image,pixel));
-  signature=pixel_list->lists[0].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[0].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,0,index);
-  index=ScaleQuantumToShort(GetPixelGreen(image,pixel));
-  signature=pixel_list->lists[1].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[1].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,1,index);
-  index=ScaleQuantumToShort(GetPixelBlue(image,pixel));
-  signature=pixel_list->lists[2].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[2].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,2,index);
-  index=ScaleQuantumToShort(GetPixelAlpha(image,pixel));
-  signature=pixel_list->lists[3].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[3].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,3,index);
-  if (image->colorspace == CMYKColorspace)
-    index=ScaleQuantumToShort(GetPixelBlack(image,pixel));
-  signature=pixel_list->lists[4].nodes[index].signature;
+  index=ScaleQuantumToShort(pixel);
+  signature=pixel_list->skip_list.nodes[index].signature;
   if (signature == pixel_list->signature)
-    pixel_list->lists[4].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,4,index);
+    {
+      pixel_list->skip_list.nodes[index].count++;
+      return;
+    }
+  AddNodePixelList(pixel_list,index);
 }
 
 static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
@@ -4512,41 +4292,38 @@ static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
   return(x);
 }
 
+static inline size_t MagickMax(const size_t x,const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
 static void ResetPixelList(PixelList *pixel_list)
 {
   int
     level;
 
-  register ListNode
+  register SkipNode
     *root;
 
   register SkipList
-    *list;
-
-  register ssize_t
-    channel;
+    *p;
 
   /*
     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;
-  }
+  p=(&pixel_list->skip_list);
+  root=p->nodes+65536UL;
+  p->level=0;
+  for (level=0; level < 9; level++)
+    root->next[level]=65536UL;
   pixel_list->seed=pixel_list->signature++;
 }
 
 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
   const size_t width,const size_t height,ExceptionInfo *exception)
 {
-#define StatisticWidth \
-  (width == 0 ? GetOptimalKernelWidth2D((double) width,0.5) : width)
-#define StatisticHeight \
-  (height == 0 ? GetOptimalKernelWidth2D((double) height,0.5) : height)
 #define StatisticImageTag  "Statistic/Image"
 
   CacheView
@@ -4566,6 +4343,7 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
     **restrict pixel_list;
 
   ssize_t
+    center,
     y;
 
   /*
@@ -4581,13 +4359,13 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
     exception);
   if (statistic_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
+  status=SetImageStorageClass(statistic_image,DirectClass,exception);
+  if (status == MagickFalse)
     {
-      InheritException(exception,&statistic_image->exception);
       statistic_image=DestroyImage(statistic_image);
       return((Image *) NULL);
     }
-  pixel_list=AcquirePixelListThreadSet(StatisticWidth,StatisticHeight);
+  pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
   if (pixel_list == (PixelList **) NULL)
     {
       statistic_image=DestroyImage(statistic_image);
@@ -4596,6 +4374,8 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
   /*
     Make each pixel the min / max / median / mode / etc. of the neighborhood.
   */
+  center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
+    (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
   status=MagickTrue;
   progress=0;
   image_view=AcquireCacheView(image);
@@ -4619,9 +4399,9 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
 
     if (status == MagickFalse)
       continue;
-    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) StatisticWidth/2L),y-
-      (ssize_t) (StatisticHeight/2L),image->columns+StatisticWidth,
-      StatisticHeight,exception);
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
+      (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
+      MagickMax(height,1),exception);
     q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns,      1,exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
@@ -4630,94 +4410,104 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
       }
     for (x=0; x < (ssize_t) statistic_image->columns; x++)
     {
-      PixelInfo
-        pixel;
-
-      register const Quantum
-        *restrict r;
-
       register ssize_t
-        u,
-        v;
+        i;
 
-      r=p;
-      ResetPixelList(pixel_list[id]);
-      for (v=0; v < (ssize_t) StatisticHeight; v++)
-      {
-        for (u=0; u < (ssize_t) StatisticWidth; u++)
-          InsertPixelList(image,r+u*GetPixelChannels(image),pixel_list[id]);
-        r+=(image->columns+StatisticWidth)*GetPixelChannels(image);
-      }
-      GetPixelInfo(image,&pixel);
-      SetPixelInfo(image,p+(StatisticWidth*StatisticHeight/2)*
-        GetPixelChannels(image),&pixel);
-      switch (type)
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        case GradientStatistic:
-        {
-          PixelInfo
-            maximum,
-            minimum;
-
-          minimum=GetMinimumPixelList(pixel_list[id]);
-          maximum=GetMaximumPixelList(pixel_list[id]);
-          pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
-          pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
-          pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
-          pixel.alpha=MagickAbsoluteValue(maximum.alpha-minimum.alpha);
-          if (image->colorspace == CMYKColorspace)
-            pixel.black=MagickAbsoluteValue(maximum.black-minimum.black);
-          break;
-        }
-        case MaximumStatistic:
-        {
-          pixel=GetMaximumPixelList(pixel_list[id]);
-          break;
-        }
-        case MeanStatistic:
-        {
-          pixel=GetMeanPixelList(pixel_list[id]);
-          break;
-        }
-        case MedianStatistic:
-        default:
-        {
-          pixel=GetMedianPixelList(pixel_list[id]);
-          break;
-        }
-        case MinimumStatistic:
-        {
-          pixel=GetMinimumPixelList(pixel_list[id]);
-          break;
-        }
-        case ModeStatistic:
-        {
-          pixel=GetModePixelList(pixel_list[id]);
-          break;
-        }
-        case NonpeakStatistic:
+        PixelChannel
+          channel;
+
+        PixelTrait
+          statistic_traits,
+          traits;
+
+        Quantum
+          pixel;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        statistic_traits=GetPixelChannelMapTraits(statistic_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (statistic_traits == UndefinedPixelTrait))
+          continue;
+        if ((statistic_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(statistic_image,channel,p[center+i],q);
+            continue;
+          }
+        pixels=p;
+        ResetPixelList(pixel_list[id]);
+        for (v=0; v < (ssize_t) MagickMax(height,1); v++)
         {
-          pixel=GetNonpeakPixelList(pixel_list[id]);
-          break;
+          for (u=0; u < (ssize_t) MagickMax(width,1); u++)
+          {
+            InsertPixelList(image,pixels[i],pixel_list[id]);
+            pixels+=GetPixelChannels(image);
+          }
+          pixels+=image->columns*GetPixelChannels(image);
         }
-        case StandardDeviationStatistic:
+        switch (type)
         {
-          pixel=GetStandardDeviationPixelList(pixel_list[id]);
-          break;
+          case GradientStatistic:
+          {
+            MagickRealType
+              maximum,
+              minimum;
+
+            minimum=(MagickRealType) GetMinimumPixelList(pixel_list[id]);
+            maximum=(MagickRealType) GetMaximumPixelList(pixel_list[id]);
+            pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
+            break;
+          }
+          case MaximumStatistic:
+          {
+            pixel=GetMaximumPixelList(pixel_list[id]);
+            break;
+          }
+          case MeanStatistic:
+          {
+            pixel=GetMeanPixelList(pixel_list[id]);
+            break;
+          }
+          case MedianStatistic:
+          default:
+          {
+            pixel=GetMedianPixelList(pixel_list[id]);
+            break;
+          }
+          case MinimumStatistic:
+          {
+            pixel=GetMinimumPixelList(pixel_list[id]);
+            break;
+          }
+          case ModeStatistic:
+          {
+            pixel=GetModePixelList(pixel_list[id]);
+            break;
+          }
+          case NonpeakStatistic:
+          {
+            pixel=GetNonpeakPixelList(pixel_list[id]);
+            break;
+          }
+          case StandardDeviationStatistic:
+          {
+            pixel=GetStandardDeviationPixelList(pixel_list[id]);
+            break;
+          }
         }
+        SetPixelChannel(statistic_image,channel,pixel,q);
       }
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(statistic_image,ClampToQuantum(pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(statistic_image,ClampToQuantum(pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(statistic_image,ClampToQuantum(pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(statistic_image,ClampToQuantum(pixel.black),q);
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->matte != MagickFalse))
-        SetPixelAlpha(statistic_image,ClampToQuantum(pixel.alpha),q);
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(statistic_image);
     }
@@ -4801,9 +4591,6 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   MagickRealType
     quantum_threshold;
 
@@ -4815,7 +4602,11 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  unsharp_image=BlurImage(image,radius,sigma,exception);
+
+
+  /* FUTURE:  use of bias on sharpen is non-sensical */
+  unsharp_image=BlurImage(image,radius,sigma,image->bias,exception);
+
   if (unsharp_image == (Image *) NULL)
     return((Image *) NULL);
   quantum_threshold=(MagickRealType) QuantumRange*threshold;
@@ -4824,7 +4615,6 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
   unsharp_view=AcquireCacheView(unsharp_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
@@ -4832,9 +4622,6 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
-    PixelInfo
-      pixel;
-
     register const Quantum
       *restrict p;
 
@@ -4854,73 +4641,41 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
         status=MagickFalse;
         continue;
       }
-    pixel=bias;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.red=GetPixelRed(image,p)-(MagickRealType) GetPixelRed(image,q);
-          if (fabs(2.0*pixel.red) < quantum_threshold)
-            pixel.red=(MagickRealType) GetPixelRed(image,p);
-          else
-            pixel.red=(MagickRealType) GetPixelRed(image,p)+(pixel.red*amount);
-          SetPixelRed(unsharp_image,ClampToQuantum(pixel.red),q);
-        }
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.green=GetPixelGreen(image,p)-
-            (MagickRealType) GetPixelGreen(image,q);
-          if (fabs(2.0*pixel.green) < quantum_threshold)
-            pixel.green=(MagickRealType)
-              GetPixelGreen(image,p);
-          else
-            pixel.green=(MagickRealType)
-              GetPixelGreen(image,p)+
-              (pixel.green*amount);
-          SetPixelGreen(unsharp_image,
-            ClampToQuantum(pixel.green),q);
-        }
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.blue=GetPixelBlue(image,p)-
-            (MagickRealType) GetPixelBlue(image,q);
-          if (fabs(2.0*pixel.blue) < quantum_threshold)
-            pixel.blue=(MagickRealType)
-              GetPixelBlue(image,p);
-          else
-            pixel.blue=(MagickRealType)
-              GetPixelBlue(image,p)+(pixel.blue*amount);
-          SetPixelBlue(unsharp_image,
-            ClampToQuantum(pixel.blue),q);
-        }
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        {
-          pixel.black=GetPixelBlack(image,p)-
-            (MagickRealType) GetPixelBlack(image,q);
-          if (fabs(2.0*pixel.black) < quantum_threshold)
-            pixel.black=(MagickRealType)
-              GetPixelBlack(image,p);
-          else
-            pixel.black=(MagickRealType)
-              GetPixelBlack(image,p)+(pixel.black*
-              amount);
-          SetPixelBlack(unsharp_image,
-            ClampToQuantum(pixel.black),q);
-        }
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.alpha=GetPixelAlpha(image,p)-
-            (MagickRealType) GetPixelAlpha(image,q);
-          if (fabs(2.0*pixel.alpha) < quantum_threshold)
-            pixel.alpha=(MagickRealType)
-              GetPixelAlpha(image,p);
-          else
-            pixel.alpha=GetPixelAlpha(image,p)+
-              (pixel.alpha*amount);
-          SetPixelAlpha(unsharp_image,
-            ClampToQuantum(pixel.alpha),q);
-        }
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits,
+          unsharp_traits;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        unsharp_traits=GetPixelChannelMapTraits(unsharp_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (unsharp_traits == UndefinedPixelTrait))
+          continue;
+        if ((unsharp_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(unsharp_image,channel,p[i],q);
+            continue;
+          }
+        pixel=p[i]-(MagickRealType) GetPixelChannel(unsharp_image,channel,q);
+        if (fabs(2.0*pixel) < quantum_threshold)
+          pixel=(MagickRealType) p[i];
+        else
+          pixel=(MagickRealType) p[i]+amount*pixel;
+        SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(unsharp_image);
     }