]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/effect.c
(no commit message)
[imagemagick] / MagickCore / effect.c
index d4ca0194162318690b61c9cf67be98cebdf7cb8b..21810c64b72bcfed634347f22088d5aa9bed44eb 100644 (file)
@@ -17,7 +17,7 @@
 %                                 October 1996                                %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 #include "MagickCore/list.h"
 #include "MagickCore/log.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/memory-private.h"
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/montage.h"
 #include "MagickCore/morphology.h"
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel-accessor.h"
+#include "MagickCore/pixel-private.h"
 #include "MagickCore/property.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum.h"
@@ -171,7 +173,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   const double sigma,ExceptionInfo *exception)
 {
 #define AdaptiveBlurImageTag  "Convolve/Image"
-#define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
+#define MagickSigma  (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
 
   CacheView
     *blur_view,
@@ -179,7 +181,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
     *image_view;
 
   double
-    **kernel,
     normalize;
 
   Image
@@ -193,6 +194,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
+  MagickRealType
+    **kernel;
+
   register ssize_t
     i;
 
@@ -215,7 +219,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     return((Image *) NULL);
-  if (fabs(sigma) <= MagickEpsilon)
+  if (fabs(sigma) < MagickEpsilon)
     return(blur_image);
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
@@ -243,8 +247,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
   width=GetOptimalKernelWidth2D(radius,sigma);
-  kernel=(double **) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
-  if (kernel == (double **) NULL)
+  kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
+    width,sizeof(*kernel)));
+  if (kernel == (MagickRealType  **) NULL)
     {
       edge_image=DestroyImage(edge_image);
       blur_image=DestroyImage(blur_image);
@@ -253,9 +258,9 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
   for (i=0; i < (ssize_t) width; i+=2)
   {
-    kernel[i]=(double *) AcquireAlignedMemory((size_t) (width-i),(width-i)*
-      sizeof(**kernel));
-    if (kernel[i] == (double *) NULL)
+    kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
+      (size_t) (width-i),(width-i)*sizeof(**kernel)));
+    if (kernel[i] == (MagickRealType *) NULL)
       break;
     normalize=0.0;
     j=(ssize_t) (width-i)/2;
@@ -264,23 +269,23 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
     {
       for (u=(-j); u <= j; u++)
       {
-        kernel[i][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+        kernel[i][k]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
           MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
         normalize+=kernel[i][k];
         k++;
       }
     }
-    if (fabs(normalize) <= MagickEpsilon)
-      normalize=1.0;
-    normalize=1.0/normalize;
+    if (fabs(normalize) < MagickEpsilon)
+      normalize=MagickEpsilon;
+    normalize=PerceptibleReciprocal(normalize);
     for (k=0; k < (j*j); k++)
       kernel[i][k]=normalize*kernel[i][k];
   }
   if (i < (ssize_t) width)
     {
       for (i-=2; i >= 0; i-=2)
-        kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
-      kernel=(double **) RelinquishAlignedMemory(kernel);
+        kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
+      kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
       edge_image=DestroyImage(edge_image);
       blur_image=DestroyImage(blur_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -290,11 +295,12 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  edge_view=AcquireCacheView(edge_image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  edge_view=AcquireVirtualCacheView(edge_image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,blur_image,blur_image->rows,1)
 #endif
   for (y=0; y < (ssize_t) blur_image->rows; y++)
   {
@@ -346,19 +352,12 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
         GetPixelChannels(image)*((width-j)/2L);
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
@@ -370,14 +369,14 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
         ssize_t
           v;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
         if (((blur_traits & CopyPixelTrait) != 0) ||
-            (GetPixelMask(image,q) != 0))
+            (GetPixelMask(image,p) != 0))
           {
             SetPixelChannel(blur_image,channel,p[center+i],q);
             continue;
@@ -386,7 +385,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
         pixels=p;
         pixel=0.0;
         gamma=0.0;
-        if ((blur_traits & BlendPixelTrait) == 0)
+        if ((GetPixelAlphaTraits(blur_image) & BlendPixelTrait) == 0)
           {
             /*
               No alpha blending.
@@ -401,7 +400,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
                 pixels+=GetPixelChannels(image);
               }
             }
-            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            gamma=PerceptibleReciprocal(gamma);
             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
             continue;
           }
@@ -412,14 +411,14 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
         {
           for (u=0; u < (ssize_t) (width-j); u++)
           {
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            alpha=(double) (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);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       q+=GetPixelChannels(blur_image);
@@ -447,8 +446,8 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
   image_view=DestroyCacheView(image_view);
   edge_image=DestroyImage(edge_image);
   for (i=0; i < (ssize_t) width;  i+=2)
-    kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
-  kernel=(double **) RelinquishAlignedMemory(kernel);
+    kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
+  kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);
@@ -492,7 +491,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   const double sigma,ExceptionInfo *exception)
 {
 #define AdaptiveSharpenImageTag  "Convolve/Image"
-#define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
+#define MagickSigma  (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
 
   CacheView
     *sharp_view,
@@ -500,7 +499,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
     *image_view;
 
   double
-    **kernel,
     normalize;
 
   Image
@@ -514,6 +512,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
+  MagickRealType
+    **kernel;
+
   register ssize_t
     i;
 
@@ -536,7 +537,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   sharp_image=CloneImage(image,0,0,MagickTrue,exception);
   if (sharp_image == (Image *) NULL)
     return((Image *) NULL);
-  if (fabs(sigma) <= MagickEpsilon)
+  if (fabs(sigma) < MagickEpsilon)
     return(sharp_image);
   if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
     {
@@ -564,8 +565,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
   width=GetOptimalKernelWidth2D(radius,sigma);
-  kernel=(double **) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
-  if (kernel == (double **) NULL)
+  kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
+    width,sizeof(*kernel)));
+  if (kernel == (MagickRealType **) NULL)
     {
       edge_image=DestroyImage(edge_image);
       sharp_image=DestroyImage(sharp_image);
@@ -574,9 +576,9 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
   for (i=0; i < (ssize_t) width; i+=2)
   {
-    kernel[i]=(double *) AcquireAlignedMemory((size_t) (width-i),(width-i)*
-      sizeof(**kernel));
-    if (kernel[i] == (double *) NULL)
+    kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
+      (size_t) (width-i),(width-i)*sizeof(**kernel)));
+    if (kernel[i] == (MagickRealType *) NULL)
       break;
     normalize=0.0;
     j=(ssize_t) (width-i)/2;
@@ -585,23 +587,23 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
     {
       for (u=(-j); u <= j; u++)
       {
-        kernel[i][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
-          MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+        kernel[i][k]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
+          MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
         normalize+=kernel[i][k];
         k++;
       }
     }
-    if (fabs(normalize) <= MagickEpsilon)
-      normalize=1.0;
-    normalize=1.0/normalize;
+    if (fabs(normalize) < MagickEpsilon)
+      normalize=MagickEpsilon;
+    normalize=PerceptibleReciprocal(normalize);
     for (k=0; k < (j*j); k++)
       kernel[i][k]=normalize*kernel[i][k];
   }
   if (i < (ssize_t) width)
     {
       for (i-=2; i >= 0; i-=2)
-        kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
-      kernel=(double **) RelinquishAlignedMemory(kernel);
+        kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
+      kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
       edge_image=DestroyImage(edge_image);
       sharp_image=DestroyImage(sharp_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -611,11 +613,12 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  edge_view=AcquireCacheView(edge_image);
-  sharp_view=AcquireCacheView(sharp_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  edge_view=AcquireVirtualCacheView(edge_image,exception);
+  sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,sharp_image,sharp_image->rows,1)
 #endif
   for (y=0; y < (ssize_t) sharp_image->rows; y++)
   {
@@ -667,19 +670,12 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
         GetPixelChannels(image)*((width-j)/2);
       for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          sharp_traits,
-          traits;
-
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
@@ -691,14 +687,14 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
         ssize_t
           v;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        sharp_traits=GetPixelChannelMapTraits(sharp_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait sharp_traits=GetPixelChannelTraits(sharp_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (sharp_traits == UndefinedPixelTrait))
           continue;
         if (((sharp_traits & CopyPixelTrait) != 0) ||
-            (GetPixelMask(image,q) != 0))
+            (GetPixelMask(image,p) != 0))
           {
             SetPixelChannel(sharp_image,channel,p[center+i],q);
             continue;
@@ -707,7 +703,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
         pixels=p;
         pixel=0.0;
         gamma=0.0;
-        if ((sharp_traits & BlendPixelTrait) == 0)
+        if ((GetPixelAlphaTraits(sharp_image) & BlendPixelTrait) == 0)
           {
             /*
               No alpha blending.
@@ -722,7 +718,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
                 pixels+=GetPixelChannels(image);
               }
             }
-            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            gamma=PerceptibleReciprocal(gamma);
             SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
             continue;
           }
@@ -733,14 +729,14 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
         {
           for (u=0; u < (ssize_t) (width-j); u++)
           {
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            alpha=(double) (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);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       q+=GetPixelChannels(sharp_image);
@@ -768,8 +764,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   image_view=DestroyCacheView(image_view);
   edge_image=DestroyImage(edge_image);
   for (i=0; i < (ssize_t) width;  i+=2)
-    kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
-  kernel=(double **) RelinquishAlignedMemory(kernel);
+    kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
+  kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     sharp_image=DestroyImage(sharp_image);
   return(sharp_image);
@@ -813,12 +809,14 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
 %
 */
 
-static double *GetBlurKernel(const size_t width,const double sigma)
+static MagickRealType *GetBlurKernel(const size_t width,const double sigma)
 {
   double
-    *kernel,
     normalize;
 
+  MagickRealType
+    *kernel;
+
   register ssize_t
     i;
 
@@ -830,16 +828,17 @@ static double *GetBlurKernel(const size_t width,const double sigma)
     Generate a 1-D convolution kernel.
   */
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
-  kernel=(double *) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
-  if (kernel == (double *) NULL)
+  kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
+    width,sizeof(*kernel)));
+  if (kernel == (MagickRealType *) NULL)
     return(0);
   normalize=0.0;
   j=(ssize_t) width/2;
   i=0;
   for (k=(-j); k <= j; k++)
   {
-    kernel[i]=(double) (exp(-((double) k*k)/(2.0*MagickSigma*MagickSigma))/
-      (MagickSQ2PI*MagickSigma));
+    kernel[i]=(MagickRealType) (exp(-((double) k*k)/(2.0*MagickSigma*
+      MagickSigma))/(MagickSQ2PI*MagickSigma));
     normalize+=kernel[i];
     i++;
   }
@@ -857,9 +856,6 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     *blur_view,
     *image_view;
 
-  double
-    *kernel;
-
   Image
     *blur_image;
 
@@ -869,6 +865,9 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
+  MagickRealType
+    *kernel;
+
   register ssize_t
     i;
 
@@ -889,10 +888,10 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     (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 (fabs(sigma) <= MagickEpsilon)
+  if (fabs(sigma) < MagickEpsilon)
     return(blur_image);
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
@@ -901,7 +900,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     }
   width=GetOptimalKernelWidth1D(radius,sigma);
   kernel=GetBlurKernel(width,sigma);
-  if (kernel == (double *) NULL)
+  if (kernel == (MagickRealType *) NULL)
     {
       blur_image=DestroyImage(blur_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -912,7 +911,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         format[MaxTextExtent],
         *message;
 
-      register const double
+      register const MagickRealType
         *k;
 
       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
@@ -924,7 +923,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         *message='\0';
         (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) i);
         (void) ConcatenateString(&message,format);
-        (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
+        (void) FormatLocaleString(format,MaxTextExtent,"%g ",(double) *k++);
         (void) ConcatenateString(&message,format);
         (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
       }
@@ -936,10 +935,11 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   status=MagickTrue;
   progress=0;
   center=(ssize_t) GetPixelChannels(image)*(width/2L);
-  image_view=AcquireCacheView(image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,blur_image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -970,19 +970,12 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
 
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
@@ -991,9 +984,9 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         register ssize_t
           u;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
@@ -1006,7 +999,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         k=kernel;
         pixels=p;
         pixel=0.0;
-        if ((blur_traits & BlendPixelTrait) == 0)
+        if ((GetPixelAlphaTraits(blur_image) & BlendPixelTrait) == 0)
           {
             /*
               No alpha blending.
@@ -1026,13 +1019,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         gamma=0.0;
         for (u=0; u < (ssize_t) width; u++)
         {
-          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+          alpha=(double) (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);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
@@ -1060,10 +1053,11 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     Blur columns.
   */
   center=(ssize_t) GetPixelChannels(blur_image)*(width/2L);
-  image_view=AcquireCacheView(blur_image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(blur_image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(blur_image,blur_image,blur_image->columns,1)
 #endif
   for (x=0; x < (ssize_t) blur_image->columns; x++)
   {
@@ -1093,19 +1087,12 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
 
       for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
@@ -1114,9 +1101,9 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         register ssize_t
           u;
 
-        channel=GetPixelChannelMapChannel(blur_image,i);
-        traits=GetPixelChannelMapTraits(blur_image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(blur_image,i);
+        PixelTrait traits=GetPixelChannelTraits(blur_image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
@@ -1129,7 +1116,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         k=kernel;
         pixels=p;
         pixel=0.0;
-        if ((blur_traits & BlendPixelTrait) == 0)
+        if ((GetPixelAlphaTraits(blur_image) & BlendPixelTrait) == 0)
           {
             /*
               No alpha blending.
@@ -1149,14 +1136,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         gamma=0.0;
         for (u=0; u < (ssize_t) width; u++)
         {
-          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(blur_image,
-            pixels));
+          alpha=(double) (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);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(blur_image);
@@ -1180,7 +1166,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   }
   blur_view=DestroyCacheView(blur_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishAlignedMemory(kernel);
+  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
   blur_image->type=image->type;
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
@@ -1217,7 +1203,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
 MagickExport Image *ConvolveImage(const Image *image,
   const KernelInfo *kernel_info,ExceptionInfo *exception)
 {
-  return(MorphologyImage(image,ConvolveMorphology,1,kernel_info,exception));
+  return(MorphologyImage(image,CorrelateMorphology,1,kernel_info,exception));
 }
 \f
 /*
@@ -1249,9 +1235,9 @@ MagickExport Image *ConvolveImage(const Image *image,
 %
 */
 
-static void Hull(const ssize_t x_offset,const ssize_t y_offset,
-  const size_t columns,const size_t rows,const int polarity,Quantum *restrict f,
-  Quantum *restrict g)
+static void Hull(const Image *image,const ssize_t x_offset,
+  const ssize_t y_offset,const size_t columns,const size_t rows,
+  const int polarity,Quantum *restrict f,Quantum *restrict g)
 {
   register Quantum
     *p,
@@ -1268,23 +1254,24 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
   q=g+(columns+2);
   r=p+(y_offset*(columns+2)+x_offset);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static)
+  #pragma omp parallel for schedule(static,4) \
+    magick_threads(image,image,1,1)
 #endif
   for (y=0; y < (ssize_t) rows; y++)
   {
+    MagickRealType
+      v;
+
     register ssize_t
       i,
       x;
 
-    SignedQuantum
-      v;
-
     i=(2*y+1)+y*columns;
     if (polarity > 0)
       for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(SignedQuantum) p[i];
-        if ((SignedQuantum) r[i] >= (v+ScaleCharToQuantum(2)))
+        v=(MagickRealType) p[i];
+        if ((MagickRealType) r[i] >= (v+ScaleCharToQuantum(2)))
           v+=ScaleCharToQuantum(1);
         q[i]=(Quantum) v;
         i++;
@@ -1292,8 +1279,8 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
     else
       for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(SignedQuantum) p[i];
-        if ((SignedQuantum) r[i] <= (v-ScaleCharToQuantum(2)))
+        v=(MagickRealType) p[i];
+        if ((MagickRealType) r[i] <= (v-ScaleCharToQuantum(2)))
           v-=ScaleCharToQuantum(1);
         q[i]=(Quantum) v;
         i++;
@@ -1304,7 +1291,8 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
   r=q+(y_offset*(columns+2)+x_offset);
   s=q-(y_offset*(columns+2)+x_offset);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static)
+  #pragma omp parallel for schedule(static,4) \
+    magick_threads(image,image,1,1)
 #endif
   for (y=0; y < (ssize_t) rows; y++)
   {
@@ -1312,16 +1300,16 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
       i,
       x;
 
-    SignedQuantum
+    MagickRealType
       v;
 
     i=(2*y+1)+y*columns;
     if (polarity > 0)
       for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(SignedQuantum) q[i];
-        if (((SignedQuantum) s[i] >= (v+ScaleCharToQuantum(2))) &&
-            ((SignedQuantum) r[i] > v))
+        v=(MagickRealType) q[i];
+        if (((MagickRealType) s[i] >= (v+ScaleCharToQuantum(2))) &&
+            ((MagickRealType) r[i] > v))
           v+=ScaleCharToQuantum(1);
         p[i]=(Quantum) v;
         i++;
@@ -1329,9 +1317,9 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
     else
       for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(SignedQuantum) q[i];
-        if (((SignedQuantum) s[i] <= (v-ScaleCharToQuantum(2))) &&
-            ((SignedQuantum) r[i] < v))
+        v=(MagickRealType) q[i];
+        if (((MagickRealType) s[i] <= (v-ScaleCharToQuantum(2))) &&
+            ((MagickRealType) r[i] < v))
           v-=ScaleCharToQuantum(1);
         p[i]=(Quantum) v;
         i++;
@@ -1404,17 +1392,10 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     Reduce speckle in the image.
   */
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
-  despeckle_view=AcquireCacheView(despeckle_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
-    PixelChannel
-       channel;
-
-    PixelTrait
-      despeckle_traits,
-      traits;
-
     register ssize_t
       k,
       x;
@@ -1423,16 +1404,16 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
       j,
       y;
 
-    if (status == MagickFalse)
-      continue;
-    channel=GetPixelChannelMapChannel(image,i);
-    traits=GetPixelChannelMapTraits(image,channel);
-    despeckle_traits=GetPixelChannelMapTraits(despeckle_image,channel);
+    PixelChannel channel=GetPixelChannelChannel(image,i);
+    PixelTrait traits=GetPixelChannelTraits(image,channel);
+    PixelTrait despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
     if ((traits == UndefinedPixelTrait) ||
         (despeckle_traits == UndefinedPixelTrait))
       continue;
     if ((despeckle_traits & CopyPixelTrait) != 0)
       continue;
+    if (status == MagickFalse)
+      continue;
     (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
     j=(ssize_t) image->columns+2;
     for (y=0; y < (ssize_t) image->rows; y++)
@@ -1457,10 +1438,10 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
     for (k=0; k < 4; k++)
     {
-      Hull(X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
-      Hull(-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
-      Hull(-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
-      Hull(X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
+      Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
+      Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
+      Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
+      Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
     }
     j=(ssize_t) image->columns+2;
     for (y=0; y < (ssize_t) image->rows; y++)
@@ -1471,8 +1452,8 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
       register Quantum
         *restrict q;
 
-      q=QueueCacheViewAuthenticPixels(despeckle_view,0,y,
-        despeckle_image->columns,1,exception);
+      q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
+        1,exception);
       if (q == (Quantum *) NULL)
         {
           status=MagickFalse;
@@ -1573,8 +1554,11 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   kernel_info->width=width;
   kernel_info->height=width;
-  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
-    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  kernel_info->x=(ssize_t) width/2;
+  kernel_info->y=(ssize_t) width/2;
+  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
+    AcquireAlignedMemory(kernel_info->width,kernel_info->width*
+    sizeof(*kernel_info->values)));
   if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
@@ -1586,11 +1570,11 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
   {
     for (u=(-j); u <= j; u++)
     {
-      kernel_info->values[i]=(-1.0);
+      kernel_info->values[i]=(MagickRealType) (-1.0);
       i++;
     }
   }
-  kernel_info->values[i/2]=(double) (width*width-1.0);
+  kernel_info->values[i/2]=(MagickRealType) (width*width-1.0);
   edge_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(edge_image);
@@ -1662,8 +1646,11 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   kernel_info->width=width;
   kernel_info->height=width;
-  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
-    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  kernel_info->x=(ssize_t) width/2;
+  kernel_info->y=(ssize_t) width/2;
+  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
+    AcquireAlignedMemory(kernel_info->width,kernel_info->width*
+    sizeof(*kernel_info->values)));
   if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
@@ -1676,8 +1663,8 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
   {
     for (u=(-j); u <= j; u++)
     {
-      kernel_info->values[i]=(double) (((u < 0) || (v < 0) ? -8.0 : 8.0)*
-        exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
+      kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
+        8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
         (2.0*MagickPI*MagickSigma*MagickSigma));
       if (u != k)
         kernel_info->values[i]=0.0;
@@ -1758,9 +1745,12 @@ 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->x=(ssize_t) width/2;
+  kernel_info->y=(ssize_t) width/2;
   kernel_info->signature=MagickSignature;
-  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
-    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
+    AcquireAlignedMemory(kernel_info->width,kernel_info->width*
+    sizeof(*kernel_info->values)));
   if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
@@ -1772,7 +1762,7 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
   {
     for (u=(-j); u <= j; u++)
     {
-      kernel_info->values[i]=(double) (exp(-((double) u*u+v*v)/(2.0*
+      kernel_info->values[i]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*
         MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
       i++;
     }
@@ -1821,9 +1811,10 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
 %
 */
 
-static double *GetMotionBlurKernel(const size_t width,const double sigma)
+static MagickRealType *GetMotionBlurKernel(const size_t width,
+  const double sigma)
 {
-  double
+  MagickRealType
     *kernel,
     normalize;
 
@@ -1834,13 +1825,14 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma)
    Generate a 1-D convolution kernel.
   */
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
-  kernel=(double *) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
-  if (kernel == (double *) NULL)
+  kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
+    width,sizeof(*kernel)));
+  if (kernel == (MagickRealType *) NULL)
     return(kernel);
   normalize=0.0;
   for (i=0; i < (ssize_t) width; i++)
   {
-    kernel[i]=(double) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
+    kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
       MagickSigma)))/(MagickSQ2PI*MagickSigma));
     normalize+=kernel[i];
   }
@@ -1857,9 +1849,6 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
     *image_view,
     *motion_view;
 
-  double
-    *kernel;
-
   Image
     *blur_image;
 
@@ -1869,6 +1858,9 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
+  MagickRealType
+    *kernel;
+
   OffsetInfo
     *offset;
 
@@ -1891,24 +1883,24 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
   assert(exception != (ExceptionInfo *) NULL);
   width=GetOptimalKernelWidth1D(radius,sigma);
   kernel=GetMotionBlurKernel(width,sigma);
-  if (kernel == (double *) NULL)
+  if (kernel == (MagickRealType *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
   if (offset == (OffsetInfo *) NULL)
     {
-      kernel=(double *) RelinquishAlignedMemory(kernel);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
     }
   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     {
-      kernel=(double *) RelinquishAlignedMemory(kernel);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
       return((Image *) NULL);
     }
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
-      kernel=(double *) RelinquishAlignedMemory(kernel);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
@@ -1925,11 +1917,12 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  motion_view=AcquireCacheView(image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  motion_view=AcquireVirtualCacheView(image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,blur_image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1959,30 +1952,23 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
 
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
         register const Quantum
           *restrict r;
 
-        register double
+        register MagickRealType
           *restrict k;
 
         register ssize_t
           j;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
@@ -2022,12 +2008,12 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
               status=MagickFalse;
               continue;
             }
-          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,r));
+          alpha=(double) (QuantumScale*GetPixelAlpha(image,r));
           pixel+=(*k)*alpha*r[i];
           gamma+=(*k)*alpha;
           k++;
         }
-        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
@@ -2051,7 +2037,7 @@ MagickExport Image *MotionBlurImage(const Image *image,const double radius,
   blur_view=DestroyCacheView(blur_view);
   motion_view=DestroyCacheView(motion_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishAlignedMemory(kernel);
+  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
   offset=(OffsetInfo *) RelinquishMagickMemory(offset);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
@@ -2107,6 +2093,9 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
     sigma,
     threshold;
 
+  extern const char
+    DefaultTileFrame[];
+
   Image
     *images,
     *montage_image,
@@ -2188,8 +2177,8 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       {
         degrees+=5.0;
         preview_image=ShearImage(thumbnail,degrees,degrees,exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"shear %gx%g",
-          degrees,2.0*degrees);
+        (void) FormatLocaleString(label,MaxTextExtent,"shear %gx%g",degrees,
+          2.0*degrees);
         break;
       }
       case RollPreview:
@@ -2206,8 +2195,8 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
         if (preview_image == (Image *) NULL)
           break;
-        (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",
-          2.0*percentage);
+        (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",2.0*
+          percentage);
         (void) ModulateImage(preview_image,factor,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
         break;
@@ -2217,8 +2206,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
         if (preview_image == (Image *) NULL)
           break;
-        (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",
-          2.0*percentage);
+        (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",2.0*percentage);
         (void) ModulateImage(preview_image,factor,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
         break;
@@ -2362,8 +2350,8 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       case SharpenPreview:
       {
         preview_image=SharpenImage(thumbnail,radius,sigma,exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",
-          radius,sigma);
+        (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",radius,
+          sigma);
         break;
       }
       case BlurPreview:
@@ -2378,10 +2366,10 @@ 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)
+        (void) BilevelImage(thumbnail,(double) (percentage*((double)
           QuantumRange+1.0))/100.0,exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",
-          (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
+        (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",(double)
+          (percentage*((double) QuantumRange+1.0))/100.0);
         break;
       }
       case EdgeDetectPreview:
@@ -2394,8 +2382,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       {
         preview_image=SpreadImage(thumbnail,radius,thumbnail->interpolate,
           exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"spread %g",
-          radius+0.5);
+        (void) FormatLocaleString(label,MaxTextExtent,"spread %g",radius+0.5);
         break;
       }
       case SolarizePreview:
@@ -2403,8 +2390,8 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
         if (preview_image == (Image *) NULL)
           break;
-        (void) SolarizeImage(preview_image,(double) QuantumRange*
-          percentage/100.0,exception);
+        (void) SolarizeImage(preview_image,(double) QuantumRange*percentage/
+          100.0,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
           (QuantumRange*percentage)/100.0);
         break;
@@ -2414,8 +2401,8 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         degrees+=10.0;
         preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
           exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"shade %gx%g",
-          degrees,degrees);
+        (void) FormatLocaleString(label,MaxTextExtent,"shade %gx%g",degrees,
+          degrees);
         break;
       }
       case RaisePreview:
@@ -2439,7 +2426,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         threshold+=0.4f;
-        (void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold,
+        (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
           threshold,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
           threshold,threshold);
@@ -2466,24 +2453,24 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         degrees+=5.0f;
         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);
+        (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",0.5*degrees,
+          2.0*degrees);
         break;
       }
       case OilPaintPreview:
       {
         preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
           exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
-          radius,sigma);
+        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",radius,
+          sigma);
         break;
       }
       case CharcoalDrawingPreview:
       {
         preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
           exception);
-        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
-          radius,sigma);
+        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",radius,
+          sigma);
         break;
       }
       case JPEGPreview:
@@ -2635,7 +2622,7 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
   MagickOffsetType
     progress;
 
-  MagickRealType
+  double
     blur_radius,
     *cos_theta,
     offset,
@@ -2675,18 +2662,18 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
   blur_center.y=(double) image->rows/2.0;
   blur_radius=hypot(blur_center.x,blur_center.y);
   n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
-  theta=DegreesToRadians(angle)/(MagickRealType) (n-1);
-  cos_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n,
+  theta=DegreesToRadians(angle)/(double) (n-1);
+  cos_theta=(double *) AcquireQuantumMemory((size_t) n,
     sizeof(*cos_theta));
-  sin_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n,
+  sin_theta=(double *) AcquireQuantumMemory((size_t) n,
     sizeof(*sin_theta));
-  if ((cos_theta == (MagickRealType *) NULL) ||
-      (sin_theta == (MagickRealType *) NULL))
+  if ((cos_theta == (double *) NULL) ||
+      (sin_theta == (double *) NULL))
     {
       blur_image=DestroyImage(blur_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
     }
-  offset=theta*(MagickRealType) (n-1)/2.0;
+  offset=theta*(double) (n-1)/2.0;
   for (i=0; i < (ssize_t) n; i++)
   {
     cos_theta[i]=cos((double) (theta*i-offset));
@@ -2697,11 +2684,12 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  radial_view=AcquireCacheView(image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  radial_view=AcquireVirtualCacheView(image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,blur_image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2726,7 +2714,7 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      MagickRealType
+      double
         radius;
 
       PointInfo
@@ -2754,26 +2742,19 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
         }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           gamma,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
         register const Quantum
           *restrict r;
 
         register ssize_t
           j;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
@@ -2801,7 +2782,7 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
               pixel+=r[i];
               gamma++;
             }
-            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            gamma=PerceptibleReciprocal(gamma);
             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
             continue;
           }
@@ -2819,7 +2800,7 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
           pixel+=GetPixelAlpha(image,r)*r[i];
           gamma+=GetPixelAlpha(image,r);
         }
-        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
@@ -2843,8 +2824,8 @@ MagickExport Image *RadialBlurImage(const Image *image,const double angle,
   blur_view=DestroyCacheView(blur_view);
   radial_view=DestroyCacheView(radial_view);
   image_view=DestroyCacheView(image_view);
-  cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
-  sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
+  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
+  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);
@@ -2892,13 +2873,12 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
 
   CacheView
     *blur_view,
-    *image_view;
-
-  double
-    *kernel;
+    *image_view,
+    *luminance_view;
 
   Image
-    *blur_image;
+    *blur_image,
+    *luminance_image;
 
   MagickBooleanType
     status;
@@ -2906,6 +2886,9 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
+  MagickRealType
+    *kernel;
+
   register ssize_t
     i;
 
@@ -2929,15 +2912,16 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
   width=GetOptimalKernelWidth1D(radius,sigma);
-  kernel=(double *) AcquireAlignedMemory((size_t) width,width*sizeof(*kernel));
-  if (kernel == (double *) NULL)
+  kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
+    width,width*sizeof(*kernel)));
+  if (kernel == (MagickRealType *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   j=(ssize_t) width/2;
   i=0;
   for (v=(-j); v <= j; v++)
   {
     for (u=(-j); u <= j; u++)
-      kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+      kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
         MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
   }
   if (image->debug != MagickFalse)
@@ -2946,7 +2930,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
         format[MaxTextExtent],
         *message;
 
-      register const double
+      register const MagickRealType
         *k;
 
       ssize_t
@@ -2965,7 +2949,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
         (void) ConcatenateString(&message,format);
         for (u=0; u < (ssize_t) width; u++)
         {
-          (void) FormatLocaleString(format,MaxTextExtent,"%+f ",*k++);
+          (void) FormatLocaleString(format,MaxTextExtent,"%+f ",(double) *k++);
           (void) ConcatenateString(&message,format);
         }
         (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
@@ -2978,6 +2962,22 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
       blur_image=DestroyImage(blur_image);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
+      return((Image *) NULL);
+    }
+  luminance_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (luminance_image == (Image *) NULL)
+    {
+      blur_image=DestroyImage(blur_image);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
+      return((Image *) NULL);
+    }
+  status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
+  if (status == MagickFalse)
+    {
+      luminance_image=DestroyImage(luminance_image);
+      blur_image=DestroyImage(blur_image);
+      kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
       return((Image *) NULL);
     }
   /*
@@ -2987,10 +2987,12 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
   progress=0;
   center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*(width/2L)+
     GetPixelChannels(image)*(width/2L));
-  image_view=AcquireCacheView(image);
-  blur_view=AcquireCacheView(blur_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  luminance_view=AcquireVirtualCacheView(luminance_image,exception);
+  blur_view=AcquireAuthenticCacheView(blur_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,blur_image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3001,6 +3003,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
       sync;
 
     register const Quantum
+      *restrict l,
       *restrict p;
 
     register Quantum
@@ -3013,6 +3016,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
       continue;
     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
       (width/2L),image->columns+width,width,exception);
+    l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) width/2L),y-(ssize_t)
+      (width/2L),luminance_image->columns+width,width,exception);
     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
@@ -3022,28 +3027,25 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
+      double
+        intensity;
+
       register ssize_t
         i;
 
+      intensity=GetPixelIntensity(image,p+center);
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           alpha,
           gamma,
-          intensity,
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          blur_traits,
-          traits;
-
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
+          *restrict luminance_pixels,
           *restrict pixels;
 
         register ssize_t
@@ -3052,9 +3054,9 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
         ssize_t
           v;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait blur_traits=GetPixelChannelTraits(blur_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (blur_traits == UndefinedPixelTrait))
           continue;
@@ -3067,7 +3069,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
         k=kernel;
         pixel=0.0;
         pixels=p;
-        intensity=(MagickRealType) GetPixelIntensity(image,p+center);
+        luminance_pixels=l;
         gamma=0.0;
         if ((blur_traits & BlendPixelTrait) == 0)
           {
@@ -3075,7 +3077,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
             {
               for (u=0; u < (ssize_t) width; u++)
               {
-                contrast=GetPixelIntensity(image,pixels)-intensity;
+                contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
+                  intensity;
                 if (fabs(contrast) < threshold)
                   {
                     pixel+=(*k)*pixels[i];
@@ -3083,15 +3086,18 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
                   }
                 k++;
                 pixels+=GetPixelChannels(image);
+                luminance_pixels+=GetPixelChannels(luminance_image);
               }
               pixels+=image->columns*GetPixelChannels(image);
+              luminance_pixels+=luminance_image->columns*
+                GetPixelChannels(luminance_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);
+            gamma=PerceptibleReciprocal(gamma);
             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
             continue;
           }
@@ -3102,25 +3108,28 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
             contrast=GetPixelIntensity(image,pixels)-intensity;
             if (fabs(contrast) < threshold)
               {
-                alpha=(MagickRealType) (QuantumScale*
-                  GetPixelAlpha(image,pixels));
+                alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
                 pixel+=(*k)*alpha*pixels[i];
                 gamma+=(*k)*alpha;
               }
             k++;
             pixels+=GetPixelChannels(image);
+            luminance_pixels+=GetPixelChannels(luminance_image);
           }
           pixels+=image->columns*GetPixelChannels(image);
+          luminance_pixels+=luminance_image->columns*
+            GetPixelChannels(luminance_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);
+        gamma=PerceptibleReciprocal(gamma);
         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
+      l+=GetPixelChannels(luminance_image);
       q+=GetPixelChannels(blur_image);
     }
     sync=SyncCacheViewAuthenticPixels(blur_view,exception);
@@ -3143,7 +3152,8 @@ MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
   blur_image->type=image->type;
   blur_view=DestroyCacheView(blur_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishAlignedMemory(kernel);
+  luminance_image=DestroyImage(luminance_image);
+  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);
@@ -3191,6 +3201,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
     *shade_view;
 
   Image
+    *linear_image,
     *shade_image;
 
   MagickBooleanType
@@ -3214,11 +3225,21 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
+  linear_image=CloneImage(image,0,0,MagickTrue,exception);
   shade_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
-  if (shade_image == (Image *) NULL)
-    return((Image *) NULL);
+  if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
+    {
+      if (linear_image != (Image *) NULL)
+        linear_image=DestroyImage(linear_image);
+      if (shade_image != (Image *) NULL)
+        shade_image=DestroyImage(shade_image);
+      return((Image *) NULL);
+    }
+  if (image->colorspace == sRGBColorspace)
+    (void) TransformImageColorspace(linear_image,RGBColorspace,exception);
   if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
     {
+      linear_image=DestroyImage(linear_image);
       shade_image=DestroyImage(shade_image);
       return((Image *) NULL);
     }
@@ -3235,14 +3256,15 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  shade_view=AcquireCacheView(shade_image);
+  image_view=AcquireVirtualCacheView(linear_image,exception);
+  shade_view=AcquireAuthenticCacheView(shade_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(linear_image,shade_image,linear_image->rows,1)
 #endif
-  for (y=0; y < (ssize_t) image->rows; y++)
+  for (y=0; y < (ssize_t) linear_image->rows; y++)
   {
-    MagickRealType
+    double
       distance,
       normal_distance,
       shade;
@@ -3264,7 +3286,8 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
 
     if (status == MagickFalse)
       continue;
-    p=GetCacheViewVirtualPixels(image_view,-1,y-1,image->columns+2,3,exception);
+    p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
+      exception);
     q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
@@ -3276,10 +3299,10 @@ 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 */
-    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++)
+    pre=p+GetPixelChannels(linear_image);
+    center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
+    post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
+    for (x=0; x < (ssize_t) linear_image->columns; x++)
     {
       register ssize_t
         i;
@@ -3287,17 +3310,20 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
       /*
         Determine the surface normal and compute shading.
       */
-      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)));
+      normal.x=(double) (
+        GetPixelIntensity(linear_image,pre-GetPixelChannels(linear_image))+
+        GetPixelIntensity(linear_image,center-GetPixelChannels(linear_image))+
+        GetPixelIntensity(linear_image,post-GetPixelChannels(linear_image))-
+        GetPixelIntensity(linear_image,pre+GetPixelChannels(linear_image))-
+        GetPixelIntensity(linear_image,center+GetPixelChannels(linear_image))-
+        GetPixelIntensity(linear_image,post+GetPixelChannels(linear_image)));
+      normal.y=(double) (
+        GetPixelIntensity(linear_image,post-GetPixelChannels(linear_image))+
+        GetPixelIntensity(linear_image,post)+
+        GetPixelIntensity(linear_image,post+GetPixelChannels(linear_image))-
+        GetPixelIntensity(linear_image,pre-GetPixelChannels(linear_image))-
+        GetPixelIntensity(linear_image,pre)-
+        GetPixelIntensity(linear_image,pre+GetPixelChannels(linear_image)));
       if ((normal.x == 0.0) && (normal.y == 0.0))
         shade=light.z;
       else
@@ -3306,29 +3332,22 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
           distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
           if (distance > MagickEpsilon)
             {
-              normal_distance=
-                normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
+              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);
             }
         }
-      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
       {
-        PixelChannel
-          channel;
-
-        PixelTrait
-          shade_traits,
-          traits;
-
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        shade_traits=GetPixelChannelMapTraits(shade_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(linear_image,i);
+        PixelTrait traits=GetPixelChannelTraits(linear_image,channel);
+        PixelTrait shade_traits=GetPixelChannelTraits(shade_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (shade_traits == UndefinedPixelTrait))
           continue;
         if (((shade_traits & CopyPixelTrait) != 0) ||
-            (GetPixelMask(image,pre) != 0))
+            (GetPixelMask(linear_image,p) != 0))
           {
             SetPixelChannel(shade_image,channel,center[i],q);
             continue;
@@ -3341,9 +3360,9 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
         SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
           center[i]),q);
       }
-      pre+=GetPixelChannels(image);
-      center+=GetPixelChannels(image);
-      post+=GetPixelChannels(image);
+      pre+=GetPixelChannels(linear_image);
+      center+=GetPixelChannels(linear_image);
+      post+=GetPixelChannels(linear_image);
       q+=GetPixelChannels(shade_image);
     }
     if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
@@ -3363,6 +3382,9 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
   }
   shade_view=DestroyCacheView(shade_view);
   image_view=DestroyCacheView(image_view);
+  linear_image=DestroyImage(linear_image);
+  if (image->colorspace == sRGBColorspace)
+    (void) TransformImageColorspace(shade_image,sRGBColorspace,exception);
   if (status == MagickFalse)
     shade_image=DestroyImage(shade_image);
   return(shade_image);
@@ -3442,9 +3464,12 @@ 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->x=(ssize_t) width/2;
+  kernel_info->y=(ssize_t) width/2;
   kernel_info->signature=MagickSignature;
-  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
-    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
+    AcquireAlignedMemory(kernel_info->width,kernel_info->width*
+    sizeof(*kernel_info->values)));
   if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
@@ -3457,7 +3482,7 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
   {
     for (u=(-j); u <= j; u++)
     {
-      kernel_info->values[i]=(double) (-exp(-((double) u*u+v*v)/(2.0*
+      kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
         MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
       normalize+=kernel_info->values[i];
       i++;
@@ -3512,7 +3537,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
     *spread_image;
 
   MagickBooleanType
-    concurrent,
     status;
 
   MagickOffsetType
@@ -3527,6 +3551,11 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   ssize_t
     y;
 
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  unsigned long
+    key;
+#endif
+
   /*
     Initialize spread image attributes.
   */
@@ -3552,12 +3581,12 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   progress=0;
   width=GetOptimalKernelWidth1D(radius,0.5);
   random_info=AcquireRandomInfoThreadSet();
-  concurrent=GetRandomSecretKey(random_info[0]) == ~0UL ? MagickTrue :
-    MagickFalse;
-  image_view=AcquireCacheView(image);
-  spread_view=AcquireCacheView(spread_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  spread_view=AcquireAuthenticCacheView(spread_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,8) shared(progress,status) omp_concurrent(concurrent)
+  key=GetRandomSecretKey(random_info[0]);
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,spread_image,image->rows,key == ~0UL)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3612,6 +3641,8 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   spread_view=DestroyCacheView(spread_view);
   image_view=DestroyCacheView(image_view);
   random_info=DestroyRandomInfoThreadSet(random_info);
+  if (status == MagickFalse)
+    spread_image=DestroyImage(spread_image);
   return(spread_image);
 }
 \f
@@ -3673,7 +3704,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  MagickRealType
+  double
     quantum_threshold;
 
   ssize_t
@@ -3687,16 +3718,17 @@ MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
   unsharp_image=BlurImage(image,radius,sigma,exception);
   if (unsharp_image == (Image *) NULL)
     return((Image *) NULL);
-  quantum_threshold=(MagickRealType) QuantumRange*threshold;
+  quantum_threshold=(double) QuantumRange*threshold;
   /*
     Unsharp-mask image.
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  unsharp_view=AcquireCacheView(unsharp_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,unsharp_image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3726,19 +3758,12 @@ MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
 
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           pixel;
 
-        PixelChannel
-          channel;
-
-        PixelTrait
-          traits,
-          unsharp_traits;
-
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        unsharp_traits=GetPixelChannelMapTraits(unsharp_image,channel);
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        PixelTrait unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (unsharp_traits == UndefinedPixelTrait))
           continue;
@@ -3748,11 +3773,11 @@ MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
             SetPixelChannel(unsharp_image,channel,p[i],q);
             continue;
           }
-        pixel=p[i]-(MagickRealType) GetPixelChannel(unsharp_image,channel,q);
+        pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
         if (fabs(2.0*pixel) < quantum_threshold)
-          pixel=(MagickRealType) p[i];
+          pixel=(double) p[i];
         else
-          pixel=(MagickRealType) p[i]+amount*pixel;
+          pixel=(double) p[i]+amount*pixel;
         SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
       }
       p+=GetPixelChannels(image);