]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/enhance.c
Add RobidouxSharp filter depreciate Bessel Filter and Static Gravity
[imagemagick] / MagickCore / enhance.c
index b3166c36d2e04efd09d83ed8b8c543bd0c653628..ca2399db09801811fd3630b38d4c4363c4bbfc66 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 ImageMagick Studio LLC, 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/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/composite-private.h"
 #include "MagickCore/enhance.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/fx.h"
 #include "MagickCore/gem.h"
+#include "MagickCore/gem-private.h"
 #include "MagickCore/geometry.h"
 #include "MagickCore/histogram.h"
 #include "MagickCore/image.h"
@@ -61,6 +63,7 @@
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/quantum.h"
 #include "MagickCore/quantum-private.h"
@@ -72,6 +75,7 @@
 #include "MagickCore/thread-private.h"
 #include "MagickCore/token.h"
 #include "MagickCore/xml-tree.h"
+#include "MagickCore/xml-tree-private.h"
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  The format of the AutoGammaImage method is:
 %
-%      MagickBooleanType AutoGammaImage(Image *image)
-%      MagickBooleanType AutoGammaImageChannel(Image *image,
-%        const ChannelType channel)
+%      MagickBooleanType AutoGammaImage(Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: The image to auto-level
 %
-%    o channel: The channels to auto-level.  If the special 'SyncChannels'
-%      flag is set all given channels is adjusted in the same way using the
-%      mean average of those channels.
+%    o exception: return any errors or warnings in this structure.
 %
 */
-
-MagickExport MagickBooleanType AutoGammaImage(Image *image)
-{
-  return(AutoGammaImageChannel(image,DefaultChannels));
-}
-
-MagickExport MagickBooleanType AutoGammaImageChannel(Image *image,
-  const ChannelType channel)
+MagickExport MagickBooleanType AutoGammaImage(Image *image,
+  ExceptionInfo *exception)
 {
-  MagickStatusType
-    status;
-
   double
     gamma,
     log_mean,
     mean,
     sans;
 
-  log_mean=log(0.5);
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
 
-  if ((channel & SyncChannels) != 0 )
+  log_mean=log(0.5);
+  if (image->channel_mask == DefaultChannels)
     {
       /*
-        Apply gamma correction equally accross all given channels
+        Apply gamma correction equally across all given channels.
       */
-      (void) GetImageChannelMean(image,channel,&mean,&sans,&image->exception);
+      (void) GetImageMean(image,&mean,&sans,exception);
       gamma=log(mean*QuantumScale)/log_mean;
-      return(LevelImageChannel(image,channel,0.0,(double)QuantumRange,gamma));
+      return(LevelImage(image,0.0,(double) QuantumRange,gamma,exception));
     }
-
   /*
     Auto-gamma each channel separately.
   */
   status=MagickTrue;
-  if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-    {
-      (void) GetImageChannelMean(image,RedChannel,&mean,&sans,
-        &image->exception);
-      gamma=log(mean*QuantumScale)/log_mean;
-      status=status && LevelImageChannel(image,RedChannel,0.0,(double)
-        QuantumRange, gamma);
-    }
-  if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-    {
-      (void) GetImageChannelMean(image,GreenChannel,&mean,&sans,
-        &image->exception);
-      gamma=log(mean*QuantumScale)/log_mean;
-      status=status && LevelImageChannel(image,GreenChannel,0.0,(double)
-        QuantumRange,gamma);
-    }
-  if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-    {
-      (void) GetImageChannelMean(image,BlueChannel,&mean,&sans,
-        &image->exception);
-      gamma=log(mean*QuantumScale)/log_mean;
-      status=status && LevelImageChannel(image,BlueChannel,0.0,(double)
-        QuantumRange,gamma);
-    }
-  if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-      (image->colorspace == CMYKColorspace))
-    {
-      (void) GetImageChannelMean(image,BlackChannel,&mean,&sans,
-        &image->exception);
-      gamma=log(mean*QuantumScale)/log_mean;
-      status=status && LevelImageChannel(image,BlackChannel,0.0,(double)
-        QuantumRange,gamma);
-    }
-  if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-      (image->matte == MagickTrue))
-    {
-      (void) GetImageChannelMean(image,OpacityChannel,&mean,&sans,
-        &image->exception);
-      gamma=log(mean*QuantumScale)/log_mean;
-      status=status && LevelImageChannel(image,OpacityChannel,0.0,(double)
-        QuantumRange,gamma);
-    }
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    ChannelType
+      channel_mask;
+
+    PixelChannel
+      channel;
+
+    PixelTrait
+      traits;
+
+    channel=GetPixelChannelMapChannel(image,i);
+    traits=GetPixelChannelMapTraits(image,channel);
+    if ((traits & UpdatePixelTrait) == 0)
+      continue;
+    channel_mask=SetPixelChannelMask(image,(ChannelType) (1 << i));
+    status=GetImageMean(image,&mean,&sans,exception);
+    gamma=log(mean*QuantumScale)/log_mean;
+    status&=LevelImage(image,0.0,(double) QuantumRange,gamma,exception);
+    (void) SetPixelChannelMask(image,channel_mask);
+    if (status == MagickFalse)
+      break;
+  }
   return(status != 0 ? MagickTrue : MagickFalse);
 }
 \f
@@ -197,32 +173,19 @@ MagickExport MagickBooleanType AutoGammaImageChannel(Image *image,
 %
 %  The format of the LevelImage method is:
 %
-%      MagickBooleanType AutoLevelImage(Image *image)
-%      MagickBooleanType AutoLevelImageChannel(Image *image,
-%        const ChannelType channel)
+%      MagickBooleanType AutoLevelImage(Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: The image to auto-level
 %
-%    o channel: The channels to auto-level.  If the special 'SyncChannels'
-%      flag is set the min/max/mean value of all given channels is used for
-%      all given channels, to all channels in the same way.
+%    o exception: return any errors or warnings in this structure.
 %
 */
-
-MagickExport MagickBooleanType AutoLevelImage(Image *image)
-{
-  return(AutoLevelImageChannel(image,DefaultChannels));
-}
-
-MagickExport MagickBooleanType AutoLevelImageChannel(Image *image,
-  const ChannelType channel)
+MagickExport MagickBooleanType AutoLevelImage(Image *image,
+  ExceptionInfo *exception)
 {
-  /*
-    This is simply a convenience function around a Min/Max Histogram Stretch
-  */
-  return MinMaxStretchImage(image, channel, 0.0, 0.0);
+  return(MinMaxStretchImage(image,0.0,0.0,1.0,exception));
 }
 \f
 /*
@@ -236,50 +199,35 @@ MagickExport MagickBooleanType AutoLevelImageChannel(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  Use BrightnessContrastImage() to change the brightness and/or contrast of
-%  an image.  It converts the brightness and contrast parameters into slope
-%  and intercept and calls a polynomical function to apply to the image.
+%  BrightnessContrastImage() changes the brightness and/or contrast of an
+%  image.  It converts the brightness and contrast parameters into slope and
+%  intercept and calls a polynomical function to apply to the image.
 %
 %  The format of the BrightnessContrastImage method is:
 %
 %      MagickBooleanType BrightnessContrastImage(Image *image,
-%        const double brightness,const double contrast)
-%      MagickBooleanType BrightnessContrastImageChannel(Image *image,
-%        const ChannelType channel,const double brightness,
-%        const double contrast)
+%        const double brightness,const double contrast,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o brightness: the brightness percent (-100 .. 100).
 %
 %    o contrast: the contrast percent (-100 .. 100).
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
 MagickExport MagickBooleanType BrightnessContrastImage(Image *image,
-  const double brightness,const double contrast)
-{
-  MagickBooleanType
-    status;
-
-  status=BrightnessContrastImageChannel(image,DefaultChannels,brightness,
-    contrast);
-  return(status);
-}
-
-MagickExport MagickBooleanType BrightnessContrastImageChannel(Image *image,
-  const ChannelType channel,const double brightness,const double contrast)
+  const double brightness,const double contrast,ExceptionInfo *exception)
 {
 #define BrightnessContastImageTag  "BrightnessContast/Image"
 
   double
     alpha,
-    intercept,
     coefficients[2],
+    intercept,
     slope;
 
   MagickBooleanType
@@ -299,8 +247,171 @@ MagickExport MagickBooleanType BrightnessContrastImageChannel(Image *image,
   intercept=brightness/100.0+((100-brightness)/200.0)*(1.0-slope);
   coefficients[0]=slope;
   coefficients[1]=intercept;
-  status=FunctionImageChannel(image,channel,PolynomialFunction,2,coefficients,
-    &image->exception);
+  status=FunctionImage(image,PolynomialFunction,2,coefficients,exception);
+  return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C l u t I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClutImage() replaces each color value in the given image, by using it as an
+%  index to lookup a replacement color value in a Color Look UP Table in the
+%  form of an image.  The values are extracted along a diagonal of the CLUT
+%  image so either a horizontal or vertial gradient image can be used.
+%
+%  Typically this is used to either re-color a gray-scale image according to a
+%  color gradient in the CLUT image, or to perform a freeform histogram
+%  (level) adjustment according to the (typically gray-scale) gradient in the
+%  CLUT image.
+%
+%  When the 'channel' mask includes the matte/alpha transparency channel but
+%  one image has no such channel it is assumed that that image is a simple
+%  gray-scale image that will effect the alpha channel values, either for
+%  gray-scale coloring (with transparent or semi-transparent colors), or
+%  a histogram adjustment of existing alpha channel values.   If both images
+%  have matte channels, direct and normal indexing is applied, which is rarely
+%  used.
+%
+%  The format of the ClutImage method is:
+%
+%      MagickBooleanType ClutImage(Image *image,Image *clut_image,
+%        const PixelInterpolateMethod method,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image, which is replaced by indexed CLUT values
+%
+%    o clut_image: the color lookup table image for replacement color values.
+%
+%    o method: the pixel interpolation method.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
+  const PixelInterpolateMethod method,ExceptionInfo *exception)
+{
+#define ClutImageTag  "Clut/Image"
+
+  CacheView
+    *clut_view,
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    *clut_map;
+
+  register ssize_t
+    i;
+
+  ssize_t adjust,
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(clut_image != (Image *) NULL);
+  assert(clut_image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+    return(MagickFalse);
+  if (IsGrayColorspace(image->colorspace) != MagickFalse)
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
+  clut_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*clut_map));
+  if (clut_map == (PixelInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Clut image.
+  */
+  status=MagickTrue;
+  progress=0;
+  adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
+  clut_view=AcquireVirtualCacheView(clut_image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    GetPixelInfo(clut_image,clut_map+i);
+    (void) InterpolatePixelInfo(clut_image,clut_view,method,
+      QuantumScale*i*(clut_image->columns-adjust),QuantumScale*i*
+      (clut_image->rows-adjust),clut_map+i,exception);
+  }
+  clut_view=DestroyCacheView(clut_view);
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    GetPixelInfo(image,&pixel);
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      GetPixelInfoPixel(image,q,&pixel);
+      pixel.red=clut_map[ScaleQuantumToMap(pixel.red)].red;
+      pixel.green=clut_map[ScaleQuantumToMap(pixel.green)].green;
+      pixel.blue=clut_map[ScaleQuantumToMap(pixel.blue)].blue;
+      pixel.black=clut_map[ScaleQuantumToMap(pixel.black)].black;
+      pixel.alpha=clut_map[ScaleQuantumToMap(pixel.alpha)].alpha;
+      SetPixelInfoPixel(image,&pixel,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_ClutImage)
+#endif
+        proceed=SetImageProgress(image,ClutImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  clut_map=(PixelInfo *) RelinquishMagickMemory(clut_map);
+  if ((clut_image->matte != MagickFalse) &&
+      ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0))
+    (void) SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
   return(status);
 }
 \f
@@ -338,7 +449,7 @@ MagickExport MagickBooleanType BrightnessContrastImageChannel(Image *image,
 %  The format of the ColorDecisionListImage method is:
 %
 %      MagickBooleanType ColorDecisionListImage(Image *image,
-%        const char *color_correction_collection)
+%        const char *color_correction_collection,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -346,9 +457,11 @@ MagickExport MagickBooleanType BrightnessContrastImageChannel(Image *image,
 %
 %    o color_correction_collection: the color correction collection in XML.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
-  const char *color_correction_collection)
+  const char *color_correction_collection,ExceptionInfo *exception)
 {
 #define ColorDecisionListCorrectImageTag  "ColorDecisionList/Image"
 
@@ -384,16 +497,13 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
     *content,
     *p;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
-  PixelPacket
+  PixelInfo
     *cdl_map;
 
   register ssize_t
@@ -417,7 +527,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (color_correction_collection == (const char *) NULL)
     return(MagickFalse);
-  ccc=NewXMLTree((const char *) color_correction_collection,&image->exception);
+  ccc=NewXMLTree((const char *) color_correction_collection,exception);
   if (ccc == (XMLTreeInfo *) NULL)
     return(MagickFalse);
   cc=GetXMLTreeChild(ccc,"ColorCorrection");
@@ -458,19 +568,18 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
             {
               case 0:
               {
-                color_correction.red.slope=InterpretLocaleValue(token,
-                  (char **) NULL);
+                color_correction.red.slope=StringToDouble(token,(char **) NULL);
                 break;
               }
               case 1:
               {
-                color_correction.green.slope=InterpretLocaleValue(token,
+                color_correction.green.slope=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
               case 2:
               {
-                color_correction.blue.slope=InterpretLocaleValue(token,
+                color_correction.blue.slope=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
@@ -491,19 +600,19 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
             {
               case 0:
               {
-                color_correction.red.offset=InterpretLocaleValue(token,
+                color_correction.red.offset=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
               case 1:
               {
-                color_correction.green.offset=InterpretLocaleValue(token,
+                color_correction.green.offset=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
               case 2:
               {
-                color_correction.blue.offset=InterpretLocaleValue(token,
+                color_correction.blue.offset=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
@@ -524,19 +633,18 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
             {
               case 0:
               {
-                color_correction.red.power=InterpretLocaleValue(token,
-                  (char **) NULL);
+                color_correction.red.power=StringToDouble(token,(char **) NULL);
                 break;
               }
               case 1:
               {
-                color_correction.green.power=InterpretLocaleValue(token,
+                color_correction.green.power=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
               case 2:
               {
-                color_correction.blue.power=InterpretLocaleValue(token,
+                color_correction.blue.power=StringToDouble(token,
                   (char **) NULL);
                 break;
               }
@@ -556,8 +664,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
           content=GetXMLTreeContent(saturation);
           p=(const char *) content;
           GetMagickToken(p,&p,token);
-          color_correction.saturation=InterpretLocaleValue(token,
-            (char **) NULL);
+          color_correction.saturation=StringToDouble(token,(char **) NULL);
         }
     }
   ccc=DestroyXMLTree(ccc);
@@ -586,24 +693,24 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
         "  color_correction.saturation: %g",color_correction.saturation);
     }
-  cdl_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*cdl_map));
-  if (cdl_map == (PixelPacket *) NULL)
+  cdl_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*cdl_map));
+  if (cdl_map == (PixelInfo *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
+  #pragma omp parallel for schedule(static,4)
 #endif
   for (i=0; i <= (ssize_t) MaxMap; i++)
   {
-    cdl_map[i].red=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
-      MagickRealType) (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
-      color_correction.red.offset,color_correction.red.power)))));
-    cdl_map[i].green=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
-      MagickRealType) (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
-      color_correction.green.offset,color_correction.green.power)))));
-    cdl_map[i].blue=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
-      MagickRealType) (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
-      color_correction.blue.offset,color_correction.blue.power)))));
+    cdl_map[i].red=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+      (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
+      color_correction.red.offset,color_correction.red.power))));
+    cdl_map[i].green=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+      (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
+      color_correction.green.offset,color_correction.green.power))));
+    cdl_map[i].blue=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+      (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
+      color_correction.blue.offset,color_correction.blue.power))));
   }
   if (image->storage_class == PseudoClass)
     {
@@ -611,7 +718,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
         Apply transfer function to colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -620,13 +727,15 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
 
         luma=0.2126*image->colormap[i].red+0.7152*image->colormap[i].green+
           0.0722*image->colormap[i].blue;
-        image->colormap[i].red=ClampToQuantum(luma+color_correction.saturation*
-          cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
-        image->colormap[i].green=ClampToQuantum(luma+
-          color_correction.saturation*cdl_map[ScaleQuantumToMap(
-          image->colormap[i].green)].green-luma);
-        image->colormap[i].blue=ClampToQuantum(luma+color_correction.saturation*
-          cdl_map[ScaleQuantumToMap(image->colormap[i].blue)].blue-luma);
+        image->colormap[i].red=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red))].red-
+          luma;
+        image->colormap[i].green=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green))].green-
+          luma;
+        image->colormap[i].blue=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue))].blue-
+          luma;
       }
     }
   /*
@@ -634,10 +743,9 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -653,7 +761,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
@@ -678,7 +786,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ColorDecisionListImageChannel)
+        #pragma omp critical (MagickCore_ColorDecisionListImageChannel)
 #endif
         proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
           progress++,image->rows);
@@ -687,7 +795,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
       }
   }
   image_view=DestroyCacheView(image_view);
-  cdl_map=(PixelPacket *) RelinquishMagickMemory(cdl_map);
+  cdl_map=(PixelInfo *) RelinquishMagickMemory(cdl_map);
   return(status);
 }
 \f
@@ -696,260 +804,66 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%     C l u t I m a g e                                                       %
+%     C o n t r a s t I m a g e                                               %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  ClutImage() replaces each color value in the given image, by using it as an
-%  index to lookup a replacement color value in a Color Look UP Table in the
-%  form of an image.  The values are extracted along a diagonal of the CLUT
-%  image so either a horizontal or vertial gradient image can be used.
-%
-%  Typically this is used to either re-color a gray-scale image according to a
-%  color gradient in the CLUT image, or to perform a freeform histogram
-%  (level) adjustment according to the (typically gray-scale) gradient in the
-%  CLUT image.
-%
-%  When the 'channel' mask includes the matte/alpha transparency channel but
-%  one image has no such channel it is assumed that that image is a simple
-%  gray-scale image that will effect the alpha channel values, either for
-%  gray-scale coloring (with transparent or semi-transparent colors), or
-%  a histogram adjustment of existing alpha channel values.   If both images
-%  have matte channels, direct and normal indexing is applied, which is rarely
-%  used.
+%  ContrastImage() enhances the intensity differences between the lighter and
+%  darker elements of the image.  Set sharpen to a MagickTrue to increase the
+%  image contrast otherwise the contrast is reduced.
 %
-%  The format of the ClutImage method is:
+%  The format of the ContrastImage method is:
 %
-%      MagickBooleanType ClutImage(Image *image,Image *clut_image)
-%      MagickBooleanType ClutImageChannel(Image *image,
-%        const ChannelType channel,Image *clut_image)
+%      MagickBooleanType ContrastImage(Image *image,
+%        const MagickBooleanType sharpen,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
-%    o image: the image, which is replaced by indexed CLUT values
+%    o image: the image.
 %
-%    o clut_image: the color lookup table image for replacement color values.
+%    o sharpen: Increase or decrease image contrast.
 %
-%    o channel: the channel.
+%    o exception: return any errors or warnings in this structure.
 %
 */
 
-MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image)
+static void Contrast(const int sign,double *red,double *green,double *blue)
 {
-  return(ClutImageChannel(image,DefaultChannels,clut_image));
+  double
+    brightness,
+    hue,
+    saturation;
+
+  /*
+    Enhance contrast: dark color become darker, light color become lighter.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  hue=0.0;
+  saturation=0.0;
+  brightness=0.0;
+  ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
+  brightness+=0.5*sign*(0.5*(sin((double) (MagickPI*(brightness-0.5)))+1.0)-
+    brightness);
+  if (brightness > 1.0)
+    brightness=1.0;
+  else
+    if (brightness < 0.0)
+      brightness=0.0;
+  ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
 }
 
-MagickExport MagickBooleanType ClutImageChannel(Image *image,
-  const ChannelType channel,const Image *clut_image)
+MagickExport MagickBooleanType ContrastImage(Image *image,
+  const MagickBooleanType sharpen,ExceptionInfo *exception)
 {
-#define ClampAlphaPixelComponent(pixel) ClampToQuantum((pixel)->alpha)
-#define ClampBlackPixelComponent(pixel) ClampToQuantum((pixel)->black)
-#define ClampBluePixelComponent(pixel) ClampToQuantum((pixel)->blue)
-#define ClampGreenPixelComponent(pixel) ClampToQuantum((pixel)->green)
-#define ClampRedPixelComponent(pixel) ClampToQuantum((pixel)->red)
-#define ClutImageTag  "Clut/Image"
+#define ContrastImageTag  "Contrast/Image"
 
   CacheView
-    *clut_view,
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
-  MagickBooleanType
-    status;
-
-  MagickOffsetType
-    progress;
-
-  PixelInfo
-    *clut_map;
-
-  register ssize_t
-    i;
-
-  ssize_t
-    adjust,
-    y;
-
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(clut_image != (Image *) NULL);
-  assert(clut_image->signature == MagickSignature);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
-    return(MagickFalse);
-  clut_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*clut_map));
-  if (clut_map == (PixelInfo *) NULL)
-    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-      image->filename);
-  /*
-    Clut image.
-  */
-  status=MagickTrue;
-  progress=0;
-  adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
-  exception=(&image->exception);
-  clut_view=AcquireCacheView(clut_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
-#endif
-  for (i=0; i <= (ssize_t) MaxMap; i++)
-  {
-    GetPixelInfo(clut_image,clut_map+i);
-    (void) InterpolatePixelInfo(clut_image,clut_view,
-      UndefinedInterpolatePixel,QuantumScale*i*(clut_image->columns-adjust),
-      QuantumScale*i*(clut_image->rows-adjust),clut_map+i,exception);
-  }
-  clut_view=DestroyCacheView(clut_view);
-  image_view=AcquireCacheView(image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
-#endif
-  for (y=0; y < (ssize_t) image->rows; y++)
-  {
-    PixelInfo
-      pixel;
-
-    register Quantum
-      *restrict q;
-
-    register ssize_t
-      x;
-
-    if (status == MagickFalse)
-      continue;
-    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
-      {
-        status=MagickFalse;
-        continue;
-      }
-    GetPixelInfo(image,&pixel);
-    for (x=0; x < (ssize_t) image->columns; x++)
-    {
-      SetPixelInfo(image,q,&pixel);
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,ClampRedPixelComponent(clut_map+
-          ScaleQuantumToMap(GetPixelRed(image,q))),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,ClampGreenPixelComponent(clut_map+
-          ScaleQuantumToMap(GetPixelGreen(image,q))),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,ClampBluePixelComponent(clut_map+
-          ScaleQuantumToMap(GetPixelBlue(image,q))),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,ClampBlackPixelComponent(clut_map+
-          ScaleQuantumToMap(GetPixelBlack(image,q))),q);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        {
-          if (clut_image->matte == MagickFalse)
-            SetPixelAlpha(image,GetPixelInfoIntensity(clut_map+
-              ScaleQuantumToMap((Quantum) GetPixelAlpha(image,q))),q);
-          else
-            if (image->matte == MagickFalse)
-              SetPixelAlpha(image,ClampAlphaPixelComponent(clut_map+
-                ScaleQuantumToMap((Quantum) GetPixelInfoIntensity(&pixel))),q);
-            else
-              SetPixelAlpha(image,ClampAlphaPixelComponent(clut_map+
-                ScaleQuantumToMap(GetPixelAlpha(image,q))),q);
-        }
-      q+=GetPixelChannels(image);
-    }
-    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
-      status=MagickFalse;
-    if (image->progress_monitor != (MagickProgressMonitor) NULL)
-      {
-        MagickBooleanType
-          proceed;
-
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ClutImageChannel)
-#endif
-        proceed=SetImageProgress(image,ClutImageTag,progress++,image->rows);
-        if (proceed == MagickFalse)
-          status=MagickFalse;
-      }
-  }
-  image_view=DestroyCacheView(image_view);
-  clut_map=(PixelInfo *) RelinquishMagickMemory(clut_map);
-  if ((clut_image->matte != MagickFalse) &&
-      ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0))
-    (void) SetImageAlphaChannel(image,ActivateAlphaChannel);
-  return(status);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%     C o n t r a s t I m a g e                                               %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  ContrastImage() enhances the intensity differences between the lighter and
-%  darker elements of the image.  Set sharpen to a MagickTrue to increase the
-%  image contrast otherwise the contrast is reduced.
-%
-%  The format of the ContrastImage method is:
-%
-%      MagickBooleanType ContrastImage(Image *image,
-%        const MagickBooleanType sharpen)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o sharpen: Increase or decrease image contrast.
-%
-*/
-
-static void Contrast(const int sign,Quantum *red,Quantum *green,Quantum *blue)
-{
-  double
-    brightness,
-    hue,
-    saturation;
-
-  /*
-    Enhance contrast: dark color become darker, light color become lighter.
-  */
-  assert(red != (Quantum *) NULL);
-  assert(green != (Quantum *) NULL);
-  assert(blue != (Quantum *) NULL);
-  hue=0.0;
-  saturation=0.0;
-  brightness=0.0;
-  ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
-  brightness+=0.5*sign*(0.5*(sin((double) (MagickPI*(brightness-0.5)))+1.0)-
-    brightness);
-  if (brightness > 1.0)
-    brightness=1.0;
-  else
-    if (brightness < 0.0)
-      brightness=0.0;
-  ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
-}
-
-MagickExport MagickBooleanType ContrastImage(Image *image,
-  const MagickBooleanType sharpen)
-{
-#define ContrastImageTag  "Contrast/Image"
-
-  CacheView
-    *image_view;
-
-  ExceptionInfo
-    *exception;
-
   int
     sign;
 
@@ -984,14 +898,13 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
-    Quantum
+    double
       blue,
       green,
       red;
@@ -1005,20 +918,20 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      red=GetPixelRed(image,q);
-      green=GetPixelGreen(image,q);
-      blue=GetPixelBlue(image,q);
+      red=(double) GetPixelRed(image,q);
+      green=(double) GetPixelGreen(image,q);
+      blue=(double) GetPixelBlue(image,q);
       Contrast(sign,&red,&green,&blue);
-      SetPixelRed(image,red,q);
-      SetPixelGreen(image,green,q);
-      SetPixelBlue(image,blue,q);
+      SetPixelRed(image,ClampToQuantum(red),q);
+      SetPixelGreen(image,ClampToQuantum(green),q);
+      SetPixelBlue(image,ClampToQuantum(blue),q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -1029,7 +942,7 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ContrastImage)
+        #pragma omp critical (MagickCore_ContrastImage)
 #endif
         proceed=SetImageProgress(image,ContrastImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1051,27 +964,22 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  The ContrastStretchImage() is a simple image enhancement technique that
-%  attempts to improve the contrast in an image by `stretching' the range of
-%  intensity values it contains to span a desired range of values. It differs
-%  from the more sophisticated histogram equalization in that it can only
-%  apply %  a linear scaling function to the image pixel values.  As a result
-%  the `enhancement' is less harsh.
+%  ContrastStretchImage() is a simple image enhancement technique that attempts
+%  to improve the contrast in an image by 'stretching' the range of intensity
+%  values it contains to span a desired range of values. It differs from the
+%  more sophisticated histogram equalization in that it can only apply a
+%  linear scaling function to the image pixel values.  As a result the
+%  'enhancement' is less harsh.
 %
 %  The format of the ContrastStretchImage method is:
 %
 %      MagickBooleanType ContrastStretchImage(Image *image,
-%        const char *levels)
-%      MagickBooleanType ContrastStretchImageChannel(Image *image,
-%        const size_t channel,const double black_point,
-%        const double white_point)
+%        const char *levels,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o black_point: the black point.
 %
 %    o white_point: the white point.
@@ -1079,48 +987,11 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
 %    o levels: Specify the levels where the black and white points have the
 %      range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.).
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
 MagickExport MagickBooleanType ContrastStretchImage(Image *image,
-  const char *levels)
-{
-  double
-    black_point,
-    white_point;
-
-  GeometryInfo
-    geometry_info;
-
-  MagickBooleanType
-    status;
-
-  MagickStatusType
-    flags;
-
-  /*
-    Parse levels.
-  */
-  if (levels == (char *) NULL)
-    return(MagickFalse);
-  flags=ParseGeometry(levels,&geometry_info);
-  black_point=geometry_info.rho;
-  white_point=(double) image->columns*image->rows;
-  if ((flags & SigmaValue) != 0)
-    white_point=geometry_info.sigma;
-  if ((flags & PercentValue) != 0)
-    {
-      black_point*=(double) QuantumRange/100.0;
-      white_point*=(double) QuantumRange/100.0;
-    }
-  if ((flags & SigmaValue) == 0)
-    white_point=(double) image->columns*image->rows-black_point;
-  status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
-    white_point);
-  return(status);
-}
-
-MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
-  const ChannelType channel,const double black_point,const double white_point)
+  const double black_point,const double white_point,ExceptionInfo *exception)
 {
 #define MaxRange(color)  ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
 #define ContrastStretchImageTag  "ContrastStretch/Image"
@@ -1128,27 +999,24 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
   CacheView
     *image_view;
 
-  double
-    intensity;
-
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
-  PixelInfo
-    black,
+  double
+    *black,
     *histogram,
     *stretch_map,
-    white;
+    *white;
 
   register ssize_t
     i;
 
+  size_t
+    number_channels;
+
   ssize_t
     y;
 
@@ -1159,21 +1027,33 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  histogram=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+  black=(double *) AcquireQuantumMemory(GetPixelChannels(image),sizeof(*black));
+  white=(double *) AcquireQuantumMemory(GetPixelChannels(image),sizeof(*white));
+  histogram=(double *) AcquireQuantumMemory(MaxMap+1UL,GetPixelChannels(image)*
     sizeof(*histogram));
-  stretch_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*stretch_map));
-  if ((histogram == (PixelInfo *) NULL) ||
-      (stretch_map == (PixelInfo *) NULL))
-    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-      image->filename);
+  stretch_map=(double *) AcquireQuantumMemory(MaxMap+1UL,
+    GetPixelChannels(image)*sizeof(*stretch_map));
+  if ((black == (double *) NULL) || (white == (double *) NULL) ||
+      (histogram == (double *) NULL) || (stretch_map == (double *) NULL))
+    {
+      if (stretch_map != (double *) NULL)
+        stretch_map=(double *) RelinquishMagickMemory(stretch_map);
+      if (histogram != (double *) NULL)
+        histogram=(double *) RelinquishMagickMemory(histogram);
+      if (white != (double *) NULL)
+        white=(double *) RelinquishMagickMemory(white);
+      if (black != (double *) NULL)
+        black=(double *) RelinquishMagickMemory(black);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
   /*
     Form histogram.
   */
   status=MagickTrue;
-  exception=(&image->exception);
-  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
-  image_view=AcquireCacheView(image);
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
+    sizeof(*histogram));
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -1190,269 +1070,132 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
         status=MagickFalse;
         continue;
       }
-    if (channel == DefaultChannels)
-      for (x=0; x < (ssize_t) image->columns; x++)
-      {
-        Quantum
-          intensity;
-
-        intensity=GetPixelIntensity(image,p);
-        histogram[ScaleQuantumToMap(intensity)].red++;
-        histogram[ScaleQuantumToMap(intensity)].green++;
-        histogram[ScaleQuantumToMap(intensity)].blue++;
-        histogram[ScaleQuantumToMap(intensity)].black++;
-        p+=GetPixelChannels(image);
-      }
-    else
-      for (x=0; x < (ssize_t) image->columns; x++)
-      {
-        if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-          histogram[ScaleQuantumToMap(GetPixelRed(image,p))].red++;
-        if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-          histogram[ScaleQuantumToMap(GetPixelGreen(image,p))].green++;
-        if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-          histogram[ScaleQuantumToMap(GetPixelBlue(image,p))].blue++;
-        if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-            (image->colorspace == CMYKColorspace))
-          histogram[ScaleQuantumToMap(GetPixelBlack(image,p))].black++;
-        if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-          histogram[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha++;
-        p+=GetPixelChannels(image);
-      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+        histogram[GetPixelChannels(image)*ScaleQuantumToMap(p[i])+i]++;
+      p+=GetPixelChannels(image);
+    }
   }
+  image_view=DestroyCacheView(image_view);
   /*
     Find the histogram boundaries by locating the black/white levels.
   */
-  black.red=0.0;
-  white.red=MaxRange(QuantumRange);
-  if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-    {
-      intensity=0.0;
-      for (i=0; i <= (ssize_t) MaxMap; i++)
-      {
-        intensity+=histogram[i].red;
-        if (intensity > black_point)
-          break;
-      }
-      black.red=(MagickRealType) i;
-      intensity=0.0;
-      for (i=(ssize_t) MaxMap; i != 0; i--)
-      {
-        intensity+=histogram[i].red;
-        if (intensity > ((double) image->columns*image->rows-white_point))
-          break;
-      }
-      white.red=(MagickRealType) i;
-    }
-  black.green=0.0;
-  white.green=MaxRange(QuantumRange);
-  if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-    {
-      intensity=0.0;
-      for (i=0; i <= (ssize_t) MaxMap; i++)
-      {
-        intensity+=histogram[i].green;
-        if (intensity > black_point)
-          break;
-      }
-      black.green=(MagickRealType) i;
-      intensity=0.0;
-      for (i=(ssize_t) MaxMap; i != 0; i--)
-      {
-        intensity+=histogram[i].green;
-        if (intensity > ((double) image->columns*image->rows-white_point))
-          break;
-      }
-      white.green=(MagickRealType) i;
-    }
-  black.blue=0.0;
-  white.blue=MaxRange(QuantumRange);
-  if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-    {
-      intensity=0.0;
-      for (i=0; i <= (ssize_t) MaxMap; i++)
-      {
-        intensity+=histogram[i].blue;
-        if (intensity > black_point)
-          break;
-      }
-      black.blue=(MagickRealType) i;
-      intensity=0.0;
-      for (i=(ssize_t) MaxMap; i != 0; i--)
-      {
-        intensity+=histogram[i].blue;
-        if (intensity > ((double) image->columns*image->rows-white_point))
-          break;
-      }
-      white.blue=(MagickRealType) i;
-    }
-  black.alpha=0.0;
-  white.alpha=MaxRange(QuantumRange);
-  if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
+  number_channels=GetPixelChannels(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
+#endif
+  for (i=0; i < (ssize_t) number_channels; i++)
+  {
+    double
+      intensity;
+
+    register ssize_t
+      j;
+
+    black[i]=0.0;
+    white[i]=MaxRange(QuantumRange);
+    intensity=0.0;
+    for (j=0; j <= (ssize_t) MaxMap; j++)
     {
-      intensity=0.0;
-      for (i=0; i <= (ssize_t) MaxMap; i++)
-      {
-        intensity+=histogram[i].alpha;
-        if (intensity > black_point)
-          break;
-      }
-      black.alpha=(MagickRealType) i;
-      intensity=0.0;
-      for (i=(ssize_t) MaxMap; i != 0; i--)
-      {
-        intensity+=histogram[i].alpha;
-        if (intensity > ((double) image->columns*image->rows-white_point))
-          break;
-      }
-      white.alpha=(MagickRealType) i;
+      intensity+=histogram[GetPixelChannels(image)*j+i];
+      if (intensity > black_point)
+        break;
     }
-  black.black=0.0;
-  white.black=MaxRange(QuantumRange);
-  if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) && (image->colorspace == CMYKColorspace))
+    black[i]=(MagickRealType) j;
+    intensity=0.0;
+    for (j=(ssize_t) MaxMap; j != 0; j--)
     {
-      intensity=0.0;
-      for (i=0; i <= (ssize_t) MaxMap; i++)
-      {
-        intensity+=histogram[i].black;
-        if (intensity > black_point)
-          break;
-      }
-      black.black=(MagickRealType) i;
-      intensity=0.0;
-      for (i=(ssize_t) MaxMap; i != 0; i--)
-      {
-        intensity+=histogram[i].black;
-        if (intensity > ((double) image->columns*image->rows-white_point))
-          break;
-      }
-      white.black=(MagickRealType) i;
+      intensity+=histogram[GetPixelChannels(image)*j+i];
+      if (intensity > ((double) image->columns*image->rows-white_point))
+        break;
     }
-  histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
+    white[i]=(MagickRealType) j;
+  }
+  histogram=(double *) RelinquishMagickMemory(histogram);
   /*
     Stretch the histogram to create the stretched image mapping.
   */
-  (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
+  (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*GetPixelChannels(image)*
+    sizeof(*stretch_map));
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i <= (ssize_t) MaxMap; i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
-    if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-      {
-        if (i < (ssize_t) black.red)
-          stretch_map[i].red=0.0;
-        else
-          if (i > (ssize_t) white.red)
-            stretch_map[i].red=(MagickRealType) QuantumRange;
-          else
-            if (black.red != white.red)
-              stretch_map[i].red=(MagickRealType) ScaleMapToQuantum(
-                (MagickRealType) (MaxMap*(i-black.red)/(white.red-black.red)));
-      }
-    if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-      {
-        if (i < (ssize_t) black.green)
-          stretch_map[i].green=0.0;
-        else
-          if (i > (ssize_t) white.green)
-            stretch_map[i].green=(MagickRealType) QuantumRange;
-          else
-            if (black.green != white.green)
-              stretch_map[i].green=(MagickRealType) ScaleMapToQuantum(
-                (MagickRealType) (MaxMap*(i-black.green)/(white.green-
-                black.green)));
-      }
-    if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-      {
-        if (i < (ssize_t) black.blue)
-          stretch_map[i].blue=0.0;
-        else
-          if (i > (ssize_t) white.blue)
-            stretch_map[i].blue=(MagickRealType) QuantumRange;
-          else
-            if (black.blue != white.blue)
-              stretch_map[i].blue=(MagickRealType) ScaleMapToQuantum(
-                (MagickRealType) (MaxMap*(i-black.blue)/(white.blue-
-                black.blue)));
-      }
-    if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-      {
-        if (i < (ssize_t) black.alpha)
-          stretch_map[i].alpha=0.0;
-        else
-          if (i > (ssize_t) white.alpha)
-            stretch_map[i].alpha=(MagickRealType) QuantumRange;
-          else
-            if (black.alpha != white.alpha)
-              stretch_map[i].alpha=(MagickRealType) ScaleMapToQuantum(
-                (MagickRealType) (MaxMap*(i-black.alpha)/(white.alpha-
-                black.alpha)));
-      }
-    if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-        (image->colorspace == CMYKColorspace))
-      {
-        if (i < (ssize_t) black.black)
-          stretch_map[i].black=0.0;
+    register ssize_t
+      j;
+
+    for (j=0; j <= (ssize_t) MaxMap; j++)
+    {
+      if (j < (ssize_t) black[i])
+        stretch_map[GetPixelChannels(image)*j+i]=0.0;
+      else
+        if (j > (ssize_t) white[i])
+          stretch_map[GetPixelChannels(image)*j+i]=(MagickRealType)
+            QuantumRange;
         else
-          if (i > (ssize_t) white.black)
-            stretch_map[i].black=(MagickRealType) QuantumRange;
-          else
-            if (black.black != white.black)
-              stretch_map[i].black=(MagickRealType) ScaleMapToQuantum(
-                (MagickRealType) (MaxMap*(i-black.black)/(white.black-
-                black.black)));
-      }
+          if (black[i] != white[i])
+            stretch_map[GetPixelChannels(image)*j+i]=(MagickRealType)
+              ScaleMapToQuantum((MagickRealType) (MaxMap*(j-black[i])/
+              (white[i]-black[i])));
+    }
   }
-  /*
-    Stretch the image.
-  */
-  if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) || (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-      (image->colorspace == CMYKColorspace)))
-    image->storage_class=DirectClass;
   if (image->storage_class == PseudoClass)
     {
+      register ssize_t
+        j;
+
       /*
-        Stretch colormap.
+        Stretch-contrast colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-      for (i=0; i < (ssize_t) image->colors; i++)
+      for (j=0; j < (ssize_t) image->colors; j++)
       {
-        if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
           {
-            if (black.red != white.red)
-              image->colormap[i].red=ClampToQuantum(stretch_map[
-                ScaleQuantumToMap(image->colormap[i].red)].red);
+            i=GetPixelChannelMapChannel(image,RedPixelChannel);
+            if (black[i] != white[i])
+              image->colormap[j].red=stretch_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].red))]+i;
           }
-        if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
           {
-            if (black.green != white.green)
-              image->colormap[i].green=ClampToQuantum(stretch_map[
-                ScaleQuantumToMap(image->colormap[i].green)].green);
+            i=GetPixelChannelMapChannel(image,GreenPixelChannel);
+            if (black[i] != white[i])
+              image->colormap[j].green=stretch_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].green))]+i;
           }
-        if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
           {
-            if (black.blue != white.blue)
-              image->colormap[i].blue=ClampToQuantum(stretch_map[
-                ScaleQuantumToMap(image->colormap[i].blue)].blue);
+            i=GetPixelChannelMapChannel(image,BluePixelChannel);
+            if (black[i] != white[i])
+              image->colormap[j].blue=stretch_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].blue))]+i;
           }
-        if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
           {
-            if (black.alpha != white.alpha)
-              image->colormap[i].alpha=ClampToQuantum(stretch_map[
-                ScaleQuantumToMap(image->colormap[i].alpha)].alpha);
+            i=GetPixelChannelMapChannel(image,AlphaPixelChannel);
+            if (black[i] != white[i])
+              image->colormap[j].alpha=stretch_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].alpha))]+i;
           }
       }
     }
   /*
-    Stretch image.
+    Stretch-contrast image.
   */
   status=MagickTrue;
   progress=0;
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1465,44 +1208,36 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        {
-          if (black.red != white.red)
-            SetPixelRed(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelRed(image,q))].red),q);
-        }
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        {
-          if (black.green != white.green)
-            SetPixelGreen(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelGreen(image,q))].green),q);
-        }
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        {
-          if (black.blue != white.blue)
-            SetPixelBlue(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelBlue(image,q))].blue),q);
-        }
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        {
-          if (black.black != white.black)
-            SetPixelBlack(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelBlack(image,q))].black),q);
-        }
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
         {
-          if (black.alpha != white.alpha)
-            SetPixelAlpha(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelAlpha(image,q))].alpha),q);
+          q+=GetPixelChannels(image);
+          continue;
         }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if (((traits & UpdatePixelTrait) == 0) || (black[i] == white[i]))
+          continue;
+        q[i]=ClampToQuantum(stretch_map[GetPixelChannels(image)*
+          ScaleQuantumToMap(q[i])+i]);
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -1513,7 +1248,7 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ContrastStretchImageChannel)
+        #pragma omp critical (MagickCore_ContrastStretchImage)
 #endif
         proceed=SetImageProgress(image,ContrastStretchImageTag,progress++,
           image->rows);
@@ -1522,7 +1257,9 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
       }
   }
   image_view=DestroyCacheView(image_view);
-  stretch_map=(PixelInfo *) RelinquishMagickMemory(stretch_map);
+  stretch_map=(double *) RelinquishMagickMemory(stretch_map);
+  white=(double *) RelinquishMagickMemory(white);
+  black=(double *) RelinquishMagickMemory(black);
   return(status);
 }
 \f
@@ -1553,34 +1290,19 @@ MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
 */
 MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
 {
-#define Enhance(weight) \
-  mean=((MagickRealType) GetPixelRed(image,r)+pixel.red)/2; \
-  distance=(MagickRealType) GetPixelRed(image,r)-(MagickRealType) pixel.red; \
+#define EnhancePixel(weight) \
+  mean=((MagickRealType) r[i]+GetPixelChannel(enhance_image,channel,q))/2.0; \
+  distance=(MagickRealType) r[i]-(MagickRealType) GetPixelChannel( \
+    enhance_image,channel,q); \
   distance_squared=QuantumScale*(2.0*((MagickRealType) QuantumRange+1.0)+ \
-     mean)*distance*distance; \
-  mean=((MagickRealType) GetPixelGreen(image,r)+pixel.green)/2; \
-  distance=(MagickRealType) GetPixelGreen(image,r)- \
-    (MagickRealType) pixel.green; \
-  distance_squared+=4.0*distance*distance; \
-  mean=((MagickRealType) GetPixelBlue(image,r)+pixel.blue)/2; \
-  distance=(MagickRealType) GetPixelBlue(image,r)- \
-    (MagickRealType) pixel.blue; \
-  distance_squared+=QuantumScale*(3.0*((MagickRealType) \
-    QuantumRange+1.0)-1.0-mean)*distance*distance; \
-  mean=((MagickRealType) GetPixelAlpha(image,r)+pixel.alpha)/2; \
-  distance=(MagickRealType) GetPixelAlpha(image,r)-(MagickRealType) pixel.alpha; \
-  distance_squared+=QuantumScale*(3.0*((MagickRealType) \
-    QuantumRange+1.0)-1.0-mean)*distance*distance; \
+    mean)*distance*distance; \
   if (distance_squared < ((MagickRealType) QuantumRange*(MagickRealType) \
       QuantumRange/25.0f)) \
     { \
-      aggregate.red+=(weight)*GetPixelRed(image,r); \
-      aggregate.green+=(weight)*GetPixelGreen(image,r); \
-      aggregate.blue+=(weight)*GetPixelBlue(image,r); \
-      aggregate.alpha+=(weight)*GetPixelAlpha(image,r); \
+      aggregate+=(weight)*r[i]; \
       total_weight+=(weight); \
     } \
-  r++;
+  r+=GetPixelChannels(image);
 #define EnhanceImageTag  "Enhance/Image"
 
   CacheView
@@ -1596,9 +1318,6 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
   MagickOffsetType
     progress;
 
-  PixelInfo
-    zero;
-
   ssize_t
     y;
 
@@ -1611,15 +1330,12 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  if ((image->columns < 5) || (image->rows < 5))
-    return((Image *) NULL);
   enhance_image=CloneImage(image,image->columns,image->rows,MagickTrue,
     exception);
   if (enhance_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(enhance_image,DirectClass,exception) == MagickFalse)
     {
-      InheritException(exception,&enhance_image->exception);
       enhance_image=DestroyImage(enhance_image);
       return((Image *) NULL);
     }
@@ -1628,11 +1344,10 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
   */
   status=MagickTrue;
   progress=0;
-  (void) ResetMagickMemory(&zero,0,sizeof(zero));
-  image_view=AcquireCacheView(image);
-  enhance_view=AcquireCacheView(enhance_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1645,9 +1360,9 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
     register ssize_t
       x;
 
-    /*
-      Read another scan line.
-    */
+    ssize_t
+      center;
+
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
@@ -1658,48 +1373,69 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
         status=MagickFalse;
         continue;
       }
+    center=(ssize_t) GetPixelChannels(image)*(2*(image->columns+4)+2);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        aggregate;
-
-      MagickRealType
-        distance,
-        distance_squared,
-        mean,
-        total_weight;
-
-      PixelPacket
-        pixel;
+      register ssize_t
+        i;
 
-      register const Quantum
-        *restrict r;
-
-      /*
-        Compute weighted average of target pixel color components.
-      */
-      aggregate=zero;
-      total_weight=0.0;
-      r=p+2*(image->columns+4)+2;
-      GetPixelPacket(image,r,&pixel);
-      r=p;
-      Enhance(5.0); Enhance(8.0); Enhance(10.0); Enhance(8.0); Enhance(5.0);
-      r=p+(image->columns+4);
-      Enhance(8.0); Enhance(20.0); Enhance(40.0); Enhance(20.0); Enhance(8.0);
-      r=p+2*(image->columns+4);
-      Enhance(10.0); Enhance(40.0); Enhance(80.0); Enhance(40.0); Enhance(10.0);
-      r=p+3*(image->columns+4);
-      Enhance(8.0); Enhance(20.0); Enhance(40.0); Enhance(20.0); Enhance(8.0);
-      r=p+4*(image->columns+4);
-      Enhance(5.0); Enhance(8.0); Enhance(10.0); Enhance(8.0); Enhance(5.0);
-      SetPixelRed(enhance_image,(Quantum) ((aggregate.red+
-        (total_weight/2)-1)/total_weight),q);
-      SetPixelGreen(enhance_image,(Quantum) ((aggregate.green+
-        (total_weight/2)-1)/total_weight),q);
-      SetPixelBlue(enhance_image,(Quantum) ((aggregate.blue+
-        (total_weight/2)-1)/total_weight),q);
-      SetPixelAlpha(enhance_image,(Quantum) ((aggregate.alpha+
-        (total_weight/2)-1)/total_weight),q);
+      if (GetPixelMask(image,p) != 0)
+        {
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(enhance_image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          aggregate,
+          distance,
+          distance_squared,
+          mean,
+          total_weight;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          enhance_traits,
+          traits;
+
+        register const Quantum
+          *restrict r;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        enhance_traits=GetPixelChannelMapTraits(enhance_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (enhance_traits == UndefinedPixelTrait))
+          continue;
+        SetPixelChannel(enhance_image,channel,p[center+i],q);
+        if ((enhance_traits & CopyPixelTrait) != 0)
+          continue;
+        /*
+          Compute weighted average of target pixel color components.
+        */
+        aggregate=0.0;
+        total_weight=0.0;
+        r=p;
+        EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
+          EnhancePixel(8.0); EnhancePixel(5.0);
+        r=p+1*GetPixelChannels(image)*(image->columns+4);
+        EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
+          EnhancePixel(20.0); EnhancePixel(8.0);
+        r=p+2*GetPixelChannels(image)*(image->columns+4);
+        EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
+          EnhancePixel(40.0); EnhancePixel(10.0);
+        r=p+3*GetPixelChannels(image)*(image->columns+4);
+        EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
+          EnhancePixel(20.0); EnhancePixel(8.0);
+        r=p+4*GetPixelChannels(image)*(image->columns+4);
+        EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
+          EnhancePixel(8.0); EnhancePixel(5.0);
+        SetPixelChannel(enhance_image,channel,ClampToQuantum(aggregate/
+          total_weight),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(enhance_image);
     }
@@ -1711,7 +1447,7 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_EnhanceImage)
+        #pragma omp critical (MagickCore_EnhanceImage)
 #endif
         proceed=SetImageProgress(image,EnhanceImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1738,51 +1474,42 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
 %
 %  The format of the EqualizeImage method is:
 %
-%      MagickBooleanType EqualizeImage(Image *image)
-%      MagickBooleanType EqualizeImageChannel(Image *image,
-%        const ChannelType channel)
+%      MagickBooleanType EqualizeImage(Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
+%    o exception: return any errors or warnings in this structure.
 %
 */
-
-MagickExport MagickBooleanType EqualizeImage(Image *image)
-{
-  return(EqualizeImageChannel(image,DefaultChannels));
-}
-
-MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
-  const ChannelType channel)
+MagickExport MagickBooleanType EqualizeImage(Image *image,
+  ExceptionInfo *exception)
 {
 #define EqualizeImageTag  "Equalize/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
-  PixelInfo
-    black,
+  MagickRealType
+    black[CompositePixelChannel],
     *equalize_map,
     *histogram,
-    intensity,
     *map,
-    white;
+    white[CompositePixelChannel];
 
   register ssize_t
     i;
 
+  size_t
+    number_channels;
+
   ssize_t
     y;
 
@@ -1793,29 +1520,32 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  equalize_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*equalize_map));
-  histogram=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*histogram));
-  map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
-  if ((equalize_map == (PixelInfo *) NULL) ||
-      (histogram == (PixelInfo *) NULL) ||
-      (map == (PixelInfo *) NULL))
+  equalize_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
+    GetPixelChannels(image)*sizeof(*equalize_map));
+  histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
+    GetPixelChannels(image)*sizeof(*histogram));
+  map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
+    GetPixelChannels(image)*sizeof(*map));
+  if ((equalize_map == (MagickRealType *) NULL) ||
+      (histogram == (MagickRealType *) NULL) ||
+      (map == (MagickRealType *) NULL))
     {
-      if (map != (PixelInfo *) NULL)
-        map=(PixelInfo *) RelinquishMagickMemory(map);
-      if (histogram != (PixelInfo *) NULL)
-        histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
-      if (equalize_map != (PixelInfo *) NULL)
-        equalize_map=(PixelInfo *) RelinquishMagickMemory(equalize_map);
+      if (map != (MagickRealType *) NULL)
+        map=(MagickRealType *) RelinquishMagickMemory(map);
+      if (histogram != (MagickRealType *) NULL)
+        histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
+      if (equalize_map != (MagickRealType *) NULL)
+        equalize_map=(MagickRealType *) RelinquishMagickMemory(equalize_map);
       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
         image->filename);
     }
   /*
     Form histogram.
   */
-  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
-  exception=(&image->exception);
+  status=MagickTrue;
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
+    sizeof(*histogram));
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -1824,114 +1554,125 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
     register ssize_t
       x;
 
-    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
     if (p == (const Quantum *) NULL)
-      break;
+      {
+        status=MagickFalse;
+        continue;
+      }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelRed(image,p))].red++;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelGreen(image,p))].green++;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelBlue(image,p))].blue++;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        histogram[ScaleQuantumToMap(GetPixelBlack(image,p))].black++;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha++;
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+        histogram[GetPixelChannels(image)*ScaleQuantumToMap(p[i])+i]++;
       p+=GetPixelChannels(image);
     }
   }
+  image_view=DestroyCacheView(image_view);
   /*
     Integrate the histogram to get the equalization map.
   */
-  (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
-  for (i=0; i <= (ssize_t) MaxMap; i++)
+  number_channels=GetPixelChannels(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
+#endif
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
-    if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-      intensity.red+=histogram[i].red;
-    if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-      intensity.green+=histogram[i].green;
-    if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-      intensity.blue+=histogram[i].blue;
-    if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-        (image->colorspace == CMYKColorspace))
-      intensity.black+=histogram[i].black;
-    if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-      intensity.alpha+=histogram[i].alpha;
-    map[i]=intensity;
+    MagickRealType
+      intensity;
+
+    register ssize_t
+      j;
+
+    intensity=0.0;
+    for (j=0; j <= (ssize_t) MaxMap; j++)
+    {
+      intensity+=histogram[GetPixelChannels(image)*j+i];
+      map[GetPixelChannels(image)*j+i]=intensity;
+    }
   }
-  black=map[0];
-  white=map[(int) MaxMap];
-  (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
+  (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*GetPixelChannels(image)*
+    sizeof(*equalize_map));
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i <= (ssize_t) MaxMap; i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
-    if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
-        (white.red != black.red))
-      equalize_map[i].red=(MagickRealType) ScaleMapToQuantum((MagickRealType)
-        ((MaxMap*(map[i].red-black.red))/(white.red-black.red)));
-    if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
-        (white.green != black.green))
-      equalize_map[i].green=(MagickRealType) ScaleMapToQuantum((MagickRealType)
-        ((MaxMap*(map[i].green-black.green))/(white.green-black.green)));
-    if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
-        (white.blue != black.blue))
-      equalize_map[i].blue=(MagickRealType) ScaleMapToQuantum((MagickRealType)
-        ((MaxMap*(map[i].blue-black.blue))/(white.blue-black.blue)));
-    if ((((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-        (image->colorspace == CMYKColorspace)) &&
-        (white.black != black.black))
-      equalize_map[i].black=(MagickRealType) ScaleMapToQuantum((MagickRealType)
-        ((MaxMap*(map[i].black-black.black))/(white.black-black.black)));
-    if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-        (white.alpha != black.alpha))
-      equalize_map[i].alpha=(MagickRealType) ScaleMapToQuantum(
-        (MagickRealType) ((MaxMap*(map[i].alpha-black.alpha))/
-        (white.alpha-black.alpha)));
+    register ssize_t
+      j;
+
+    black[i]=map[i];
+    white[i]=map[GetPixelChannels(image)*MaxMap+i];
+    if (black[i] != white[i])
+      for (j=0; j <= (ssize_t) MaxMap; j++)
+        equalize_map[GetPixelChannels(image)*j+i]=(MagickRealType)
+          ScaleMapToQuantum((MagickRealType) ((MaxMap*(map[
+          GetPixelChannels(image)*j+i]-black[i]))/(white[i]-black[i])));
   }
-  histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
-  map=(PixelInfo *) RelinquishMagickMemory(map);
+  histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
+  map=(MagickRealType *) RelinquishMagickMemory(map);
   if (image->storage_class == PseudoClass)
     {
+      PixelChannel
+        channel;
+
+      register ssize_t
+        j;
+
       /*
         Equalize colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-      for (i=0; i < (ssize_t) image->colors; i++)
+      for (j=0; j < (ssize_t) image->colors; j++)
       {
-        if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
-            (white.red != black.red))
-          image->colormap[i].red=ClampToQuantum(equalize_map[
-            ScaleQuantumToMap(image->colormap[i].red)].red);
-        if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
-            (white.green != black.green))
-          image->colormap[i].green=ClampToQuantum(equalize_map[
-            ScaleQuantumToMap(image->colormap[i].green)].green);
-        if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
-            (white.blue != black.blue))
-          image->colormap[i].blue=ClampToQuantum(equalize_map[
-            ScaleQuantumToMap(image->colormap[i].blue)].blue);
-        if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-            (white.alpha != black.alpha))
-          image->colormap[i].alpha=ClampToQuantum(equalize_map[
-            ScaleQuantumToMap(image->colormap[i].alpha)].alpha);
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+          {
+            channel=GetPixelChannelMapChannel(image,RedPixelChannel);
+            if (black[channel] != white[channel])
+              image->colormap[j].red=equalize_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].red))]+
+                channel;
+          }
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+          {
+            channel=GetPixelChannelMapChannel(image,GreenPixelChannel);
+            if (black[channel] != white[channel])
+              image->colormap[j].green=equalize_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].green))]+
+                channel;
+          }
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+          {
+            channel=GetPixelChannelMapChannel(image,BluePixelChannel);
+            if (black[channel] != white[channel])
+              image->colormap[j].blue=equalize_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].blue))]+
+                channel;
+          }
+        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+          {
+            channel=GetPixelChannelMapChannel(image,AlphaPixelChannel);
+            if (black[channel] != white[channel])
+              image->colormap[j].alpha=equalize_map[GetPixelChannels(image)*
+                ScaleQuantumToMap(ClampToQuantum(image->colormap[j].alpha))]+
+                channel;
+          }
       }
     }
   /*
     Equalize image.
   */
-  status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1944,34 +1685,36 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
-          (white.red != black.red))
-        SetPixelRed(image,ClampToQuantum(equalize_map[
-          ScaleQuantumToMap(GetPixelRed(image,q))].red),q);
-      if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
-          (white.green != black.green))
-        SetPixelGreen(image,ClampToQuantum(equalize_map[
-          ScaleQuantumToMap(GetPixelGreen(image,q))].green),q);
-      if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
-          (white.blue != black.blue))
-        SetPixelBlue(image,ClampToQuantum(equalize_map[
-          ScaleQuantumToMap(GetPixelBlue(image,q))].blue),q);
-      if ((((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace)) &&
-          (white.black != black.black))
-        SetPixelBlack(image,ClampToQuantum(equalize_map[
-          ScaleQuantumToMap(GetPixelBlack(image,q))].black),q);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-          (white.alpha != black.alpha))
-        SetPixelAlpha(image,ClampToQuantum(equalize_map[
-          ScaleQuantumToMap(GetPixelAlpha(image,q))].alpha),q);
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if (((traits & UpdatePixelTrait) == 0) || (black[i] == white[i]))
+          continue;
+        q[i]=ClampToQuantum(equalize_map[GetPixelChannels(image)*
+          ScaleQuantumToMap(q[i])+i]);
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -1982,7 +1725,7 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_EqualizeImageChannel)
+        #pragma omp critical (MagickCore_EqualizeImage)
 #endif
         proceed=SetImageProgress(image,EqualizeImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1990,7 +1733,7 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
       }
   }
   image_view=DestroyCacheView(image_view);
-  equalize_map=(PixelInfo *) RelinquishMagickMemory(equalize_map);
+  equalize_map=(MagickRealType *) RelinquishMagickMemory(equalize_map);
   return(status);
 }
 \f
@@ -2013,75 +1756,29 @@ MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
 %
 %  You can also reduce the influence of a particular channel with a gamma
 %  value of 0.
-%
-%  The format of the GammaImage method is:
-%
-%      MagickBooleanType GammaImage(Image *image,const char *level)
-%      MagickBooleanType GammaImageChannel(Image *image,
-%        const ChannelType channel,const double gamma)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o channel: the channel.
-%
-%    o level: the image gamma as a string (e.g. 1.6,1.2,1.0).
-%
-%    o gamma: the image gamma.
-%
-*/
-MagickExport MagickBooleanType GammaImage(Image *image,const char *level)
-{
-  GeometryInfo
-    geometry_info;
-
-  PixelInfo
-    gamma;
-
-  MagickStatusType
-    flags,
-    status;
-
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (level == (char *) NULL)
-    return(MagickFalse);
-  flags=ParseGeometry(level,&geometry_info);
-  gamma.red=geometry_info.rho;
-  gamma.green=geometry_info.sigma;
-  if ((flags & SigmaValue) == 0)
-    gamma.green=gamma.red;
-  gamma.blue=geometry_info.xi;
-  if ((flags & XiValue) == 0)
-    gamma.blue=gamma.red;
-  if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
-    return(MagickTrue);
-  if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
-    status=GammaImageChannel(image,(const ChannelType) (RedChannel |
-      GreenChannel | BlueChannel),(double) gamma.red);
-  else
-    {
-      status=GammaImageChannel(image,RedChannel,(double) gamma.red);
-      status|=GammaImageChannel(image,GreenChannel,(double) gamma.green);
-      status|=GammaImageChannel(image,BlueChannel,(double) gamma.blue);
-    }
-  return(status != 0 ? MagickTrue : MagickFalse);
-}
-
-MagickExport MagickBooleanType GammaImageChannel(Image *image,
-  const ChannelType channel,const double gamma)
+%
+%  The format of the GammaImage method is:
+%
+%      MagickBooleanType GammaImage(Image *image,const double gamma,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o level: the image gamma as a string (e.g. 1.6,1.2,1.0).
+%
+%    o gamma: the image gamma.
+%
+*/
+MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
+  ExceptionInfo *exception)
 {
 #define GammaCorrectImageTag  "GammaCorrect/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -2112,34 +1809,34 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
       image->filename);
   (void) ResetMagickMemory(gamma_map,0,(MaxMap+1)*sizeof(*gamma_map));
   if (gamma != 0.0)
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (MaxMap > 256)
+    #pragma omp parallel for
 #endif
     for (i=0; i <= (ssize_t) MaxMap; i++)
-      gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
-        MagickRealType) (MaxMap*pow((double) i/MaxMap,1.0/gamma))));
+      gamma_map[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*pow((double) i/
+        MaxMap,1.0/gamma)));
   if (image->storage_class == PseudoClass)
     {
       /*
         Gamma-correct colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
-        if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].red=gamma_map[
-            ScaleQuantumToMap(image->colormap[i].red)];
-        if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].green=gamma_map[
-            ScaleQuantumToMap(image->colormap[i].green)];
-        if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].blue=gamma_map[
-            ScaleQuantumToMap(image->colormap[i].blue)];
-        if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].alpha=gamma_map[
-            ScaleQuantumToMap(image->colormap[i].alpha)];
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].red=(MagickRealType) gamma_map[
+            ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red))];
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].green=(MagickRealType) gamma_map[
+            ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green))];
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].blue=(MagickRealType) gamma_map[
+            ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue))];
+        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].alpha=(MagickRealType) gamma_map[
+            ScaleQuantumToMap(ClampToQuantum(image->colormap[i].alpha))];
       }
     }
   /*
@@ -2147,10 +1844,9 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2163,50 +1859,37 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if (channel == DefaultChannels)
-        {
-          SetPixelRed(image,gamma_map[
-            ScaleQuantumToMap(GetPixelRed(image,q))],q);
-          SetPixelGreen(image,gamma_map[
-            ScaleQuantumToMap(GetPixelGreen(image,q))],q);
-          SetPixelBlue(image,gamma_map[ScaleQuantumToMap(
-            GetPixelBlue(image,q))],q);
-        }
-      else
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
         {
-          if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-            SetPixelRed(image,gamma_map[ScaleQuantumToMap(
-              GetPixelRed(image,q))],q);
-          if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-            SetPixelGreen(image,gamma_map[
-              ScaleQuantumToMap(GetPixelGreen(image,q))],q);
-          if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-            SetPixelBlue(image,gamma_map[
-              ScaleQuantumToMap(GetPixelBlue(image,q))],q);
-          if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-            {
-              if (image->matte == MagickFalse)
-                SetPixelAlpha(image,gamma_map[
-                  ScaleQuantumToMap(GetPixelAlpha(image,q))],q);
-              else
-                SetPixelAlpha(image,gamma_map[
-                  ScaleQuantumToMap(GetPixelAlpha(image,q))],q);
-            }
+          q+=GetPixelChannels(image);
+          continue;
         }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=gamma_map[ScaleQuantumToMap(q[i])];
+      }
       q+=GetPixelChannels(image);
     }
-    if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-        (image->colorspace == CMYKColorspace))
-      for (x=0; x < (ssize_t) image->columns; x++)
-        SetPixelBlack(image,gamma_map[ScaleQuantumToMap(
-          GetPixelBlack(image,q))],q);
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
       status=MagickFalse;
     if (image->progress_monitor != (MagickProgressMonitor) NULL)
@@ -2215,7 +1898,7 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_GammaImageChannel)
+        #pragma omp critical (MagickCore_GammaImage)
 #endif
         proceed=SetImageProgress(image,GammaCorrectImageTag,progress++,
           image->rows);
@@ -2249,9 +1932,8 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
 %
 %  The format of the HaldClutImage method is:
 %
-%      MagickBooleanType HaldClutImage(Image *image,Image *hald_image)
-%      MagickBooleanType HaldClutImageChannel(Image *image,
-%        const ChannelType channel,Image *hald_image)
+%      MagickBooleanType HaldClutImage(Image *image,Image *hald_image,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2259,7 +1941,7 @@ MagickExport MagickBooleanType GammaImageChannel(Image *image,
 %
 %    o hald_image: the color lookup table image for replacement color values.
 %
-%    o channel: the channel.
+%    o exception: return any errors or warnings in this structure.
 %
 */
 
@@ -2271,13 +1953,7 @@ static inline size_t MagickMin(const size_t x,const size_t y)
 }
 
 MagickExport MagickBooleanType HaldClutImage(Image *image,
-  const Image *hald_image)
-{
-  return(HaldClutImageChannel(image,DefaultChannels,hald_image));
-}
-
-MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
-  const ChannelType channel,const Image *hald_image)
+  const Image *hald_image,ExceptionInfo *exception)
 {
 #define HaldClutImageTag  "Clut/Image"
 
@@ -2296,9 +1972,6 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
   double
     width;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -2322,10 +1995,12 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(hald_image != (Image *) NULL);
   assert(hald_image->signature == MagickSignature);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  if (IsGrayColorspace(image->colorspace) != MagickFalse)
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
   if (image->matte == MagickFalse)
-    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   /*
     Hald clut image.
   */
@@ -2337,27 +2012,13 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
   cube_size=level*level;
   width=(double) hald_image->columns;
   GetPixelInfo(hald_image,&zero);
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
-  hald_view=AcquireCacheView(hald_image);
+  hald_view=AcquireVirtualCacheView(hald_image,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
-    double
-      offset;
-
-    HaldInfo
-      point;
-
-    PixelInfo
-      pixel,
-      pixel1,
-      pixel2,
-      pixel3,
-      pixel4;
-
     register Quantum
       *restrict q;
 
@@ -2367,18 +2028,26 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
-    pixel=zero;
-    pixel1=zero;
-    pixel2=zero;
-    pixel3=zero;
-    pixel4=zero;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
+      double
+        offset;
+
+      HaldInfo
+        point;
+
+      PixelInfo
+        pixel,
+        pixel1,
+        pixel2,
+        pixel3,
+        pixel4;
+
       point.x=QuantumScale*(level-1.0)*GetPixelRed(image,q);
       point.y=QuantumScale*(level-1.0)*GetPixelGreen(image,q);
       point.z=QuantumScale*(level-1.0)*GetPixelBlue(image,q);
@@ -2386,41 +2055,38 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
       point.x-=floor(point.x);
       point.y-=floor(point.y);
       point.z-=floor(point.z);
-      (void) InterpolatePixelInfo(image,hald_view,
-        UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
-        &pixel1,exception);
-      (void) InterpolatePixelInfo(image,hald_view,
-        UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
-        width),&pixel2,exception);
-      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,
-        pixel2.alpha,point.y,&pixel3);
+      pixel1=zero;
+      (void) InterpolatePixelInfo(image,hald_view,image->interpolate,
+        fmod(offset,width),floor(offset/width),&pixel1,exception);
+      pixel2=zero;
+      (void) InterpolatePixelInfo(image,hald_view,image->interpolate,
+        fmod(offset+level,width),floor((offset+level)/width),&pixel2,exception);
+      pixel3=zero;
+      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,pixel2.alpha,
+        point.y,&pixel3);
       offset+=cube_size;
-      (void) InterpolatePixelInfo(image,hald_view,
-        UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
-        &pixel1,exception);
-      (void) InterpolatePixelInfo(image,hald_view,
-        UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
-        width),&pixel2,exception);
-      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,
-        pixel2.alpha,point.y,&pixel4);
-      CompositePixelInfoAreaBlend(&pixel3,pixel3.alpha,&pixel4,
-        pixel4.alpha,point.z,&pixel);
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,
-          ClampToQuantum(pixel.red),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,
-          ClampToQuantum(pixel.green),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,
-          ClampToQuantum(pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+      (void) InterpolatePixelInfo(image,hald_view,image->interpolate,
+        fmod(offset,width),floor(offset/width),&pixel1,exception);
+      (void) InterpolatePixelInfo(image,hald_view,image->interpolate,
+        fmod(offset+level,width),floor((offset+level)/width),&pixel2,exception);
+      pixel4=zero;
+      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,pixel2.alpha,
+        point.y,&pixel4);
+      pixel=zero;
+      CompositePixelInfoAreaBlend(&pixel3,pixel3.alpha,&pixel4,pixel4.alpha,
+        point.z,&pixel);
+      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+        SetPixelRed(image,ClampToQuantum(pixel.red),q);
+      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+        SetPixelGreen(image,ClampToQuantum(pixel.green),q);
+      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+        SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
+      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
           (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,
-          ClampToQuantum(pixel.black),q);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) && (image->matte != MagickFalse))
-        SetPixelAlpha(image,
-          ClampToQuantum(pixel.alpha),q);
+        SetPixelBlack(image,ClampToQuantum(pixel.black),q);
+      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
+          (image->matte != MagickFalse))
+        SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -2431,7 +2097,7 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_HaldClutImageChannel)
+        #pragma omp critical (MagickCore_HaldClutImage)
 #endif
         proceed=SetImageProgress(image,HaldClutImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2466,133 +2132,58 @@ MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
 %
 %  If a '!' flag is given, map black and white colors to the given levels
 %  rather than mapping those levels to black and white.  See
-%  LevelizeImageChannel() and LevelizeImageChannel(), below.
+%  LevelizeImage() below.
 %
 %  Gamma specifies a gamma correction to apply to the image.
 %
 %  The format of the LevelImage method is:
 %
-%      MagickBooleanType LevelImage(Image *image,const char *levels)
+%      MagickBooleanType LevelImage(Image *image,const double black_point,
+%        const double white_point,const double gamma,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o levels: Specify the levels where the black and white points have the
-%      range of 0-QuantumRange, and gamma has the range 0-10 (e.g. 10x90%+2).
-%      A '!' flag inverts the re-mapping.
+%    o black_point: The level to map zero (black) to.
+%
+%    o white_point: The level to map QuantumRange (white) to.
+%
+%    o exception: return any errors or warnings in this structure.
 %
 */
 
-MagickExport MagickBooleanType LevelImage(Image *image,const char *levels)
+static inline MagickRealType LevelPixel(const double black_point,
+  const double white_point,const double gamma,const MagickRealType pixel)
 {
   double
-    black_point,
-    gamma,
-    white_point;
-
-  GeometryInfo
-    geometry_info;
-
-  MagickBooleanType
-    status;
-
-  MagickStatusType
-    flags;
+    level_pixel,
+    scale;
 
-  /*
-    Parse levels.
-  */
-  if (levels == (char *) NULL)
-    return(MagickFalse);
-  flags=ParseGeometry(levels,&geometry_info);
-  black_point=geometry_info.rho;
-  white_point=(double) QuantumRange;
-  if ((flags & SigmaValue) != 0)
-    white_point=geometry_info.sigma;
-  gamma=1.0;
-  if ((flags & XiValue) != 0)
-    gamma=geometry_info.xi;
-  if ((flags & PercentValue) != 0)
-    {
-      black_point*=(double) image->columns*image->rows/100.0;
-      white_point*=(double) image->columns*image->rows/100.0;
-    }
-  if ((flags & SigmaValue) == 0)
-    white_point=(double) QuantumRange-black_point;
-  if ((flags & AspectValue ) == 0)
-    status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
-      gamma);
-  else
-    status=LevelizeImage(image,black_point,white_point,gamma);
-  return(status);
+  if (pixel < black_point)
+    return(0.0);
+  if (pixel > white_point)
+    return((MagickRealType) QuantumRange);
+  scale=(white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
+  level_pixel=(MagickRealType) QuantumRange*pow(scale*((double) pixel-
+    black_point),1.0/gamma);
+  return(level_pixel);
 }
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%     L e v e l i z e I m a g e                                               %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  LevelizeImage() applies the normal level operation to the image, spreading
-%  out the values between the black and white points over the entire range of
-%  values.  Gamma correction is also applied after the values has been mapped.
-%
-%  It is typically used to improve image contrast, or to provide a controlled
-%  linear threshold for the image. If the black and white points are set to
-%  the minimum and maximum values found in the image, the image can be
-%  normalized.  or by swapping black and white values, negate the image.
-%
-%  The format of the LevelizeImage method is:
-%
-%      MagickBooleanType LevelizeImage(Image *image,const double black_point,
-%        const double white_point,const double gamma)
-%      MagickBooleanType LevelizeImageChannel(Image *image,
-%        const ChannelType channel,const double black_point,
-%        const double white_point,const double gamma)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o channel: the channel.
-%
-%    o black_point: The level which is to be mapped to zero (black)
-%
-%    o white_point: The level which is to be mapped to QuantiumRange (white)
-%
-%    o gamma: adjust gamma by this factor before mapping values.
-%             use 1.0 for purely linear stretching of image color values
-%
-*/
-MagickExport MagickBooleanType LevelImageChannel(Image *image,
-  const ChannelType channel,const double black_point,const double white_point,
-  const double gamma)
+
+MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
+  const double white_point,const double gamma,ExceptionInfo *exception)
 {
 #define LevelImageTag  "Level/Image"
-#define LevelQuantum(x) (ClampToQuantum((MagickRealType) QuantumRange* \
-  pow(scale*((double) (x)-black_point),1.0/gamma)))
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
-  register double
-    scale;
-
   register ssize_t
     i;
 
@@ -2606,34 +2197,36 @@ MagickExport MagickBooleanType LevelImageChannel(Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  scale=(white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
   if (image->storage_class == PseudoClass)
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+    #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
     for (i=0; i < (ssize_t) image->colors; i++)
     {
       /*
         Level colormap.
       */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].red=LevelQuantum(image->colormap[i].red);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].green=LevelQuantum(image->colormap[i].green);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].blue=LevelQuantum(image->colormap[i].blue);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].alpha=LevelQuantum(image->colormap[i].alpha);
+      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].red=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].red));
+      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].green=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].green));
+      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].blue=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].blue));
+      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].alpha=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].alpha));
       }
   /*
     Level image.
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2646,30 +2239,36 @@ MagickExport MagickBooleanType LevelImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,LevelQuantum(
-          GetPixelRed(image,q)),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,
-          LevelQuantum(GetPixelGreen(image,q)),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,
-          LevelQuantum(GetPixelBlue(image,q)),q);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-          (image->matte == MagickTrue))
-        SetPixelAlpha(image,
-          LevelQuantum(GetPixelAlpha(image,q)),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,
-          LevelQuantum(GetPixelBlack(image,q)),q);
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=ClampToQuantum(LevelPixel(black_point,white_point,gamma,
+          (MagickRealType) q[i]));
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -2680,7 +2279,7 @@ MagickExport MagickBooleanType LevelImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_LevelImageChannel)
+        #pragma omp critical (MagickCore_LevelImage)
 #endif
         proceed=SetImageProgress(image,LevelImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2696,70 +2295,55 @@ MagickExport MagickBooleanType LevelImageChannel(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%     L e v e l i z e I m a g e C h a n n e l                                 %
+%     L e v e l i z e I m a g e                                               %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  LevelizeImageChannel() applies the reversed LevelImage() operation to just
+%  LevelizeImage() applies the reversed LevelImage() operation to just
 %  the specific channels specified.  It compresses the full range of color
 %  values, so that they lie between the given black and white points. Gamma is
 %  applied before the values are mapped.
 %
-%  LevelizeImageChannel() can be called with by using a +level command line
+%  LevelizeImage() can be called with by using a +level command line
 %  API option, or using a '!' on a -level or LevelImage() geometry string.
 %
-%  It can be used for example de-contrast a greyscale image to the exact
-%  levels specified.  Or by using specific levels for each channel of an image
-%  you can convert a gray-scale image to any linear color gradient, according
-%  to those levels.
+%  It can be used to de-contrast a greyscale image to the exact levels
+%  specified.  Or by using specific levels for each channel of an image you
+%  can convert a gray-scale image to any linear color gradient, according to
+%  those levels.
 %
-%  The format of the LevelizeImageChannel method is:
+%  The format of the LevelizeImage method is:
 %
-%      MagickBooleanType LevelizeImageChannel(Image *image,
-%        const ChannelType channel,const char *levels)
+%      MagickBooleanType LevelizeImage(Image *image,const double black_point,
+%        const double white_point,const double gamma,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o black_point: The level to map zero (black) to.
 %
-%    o white_point: The level to map QuantiumRange (white) to.
+%    o white_point: The level to map QuantumRange (white) to.
 %
 %    o gamma: adjust gamma by this factor before mapping values.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
 MagickExport MagickBooleanType LevelizeImage(Image *image,
-  const double black_point,const double white_point,const double gamma)
-{
-  MagickBooleanType
-    status;
-
-  status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
-    gamma);
-  return(status);
-}
-
-MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
-  const ChannelType channel,const double black_point,const double white_point,
-  const double gamma)
+  const double black_point,const double white_point,const double gamma,
+  ExceptionInfo *exception)
 {
 #define LevelizeImageTag  "Levelize/Image"
 #define LevelizeValue(x) (ClampToQuantum(((MagickRealType) \
-  pow((double)(QuantumScale*(x)),1.0/gamma))*(white_point-black_point)+ \
+  pow((double) (QuantumScale*(x)),1.0/gamma))*(white_point-black_point)+ \
   black_point))
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -2781,31 +2365,34 @@ MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (image->storage_class == PseudoClass)
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+    #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
     for (i=0; i < (ssize_t) image->colors; i++)
     {
       /*
         Level colormap.
       */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].red=LevelizeValue(image->colormap[i].red);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].green=LevelizeValue(image->colormap[i].green);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        image->colormap[i].alpha=LevelizeValue(image->colormap[i].alpha);
+      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].red=(double) LevelizeValue(
+          image->colormap[i].red);
+      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].green=(double) LevelizeValue(
+          image->colormap[i].green);
+      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].blue=(double) LevelizeValue(
+          image->colormap[i].blue);
+      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        image->colormap[i].alpha=(double) LevelizeValue(
+          image->colormap[i].alpha);
     }
   /*
     Level image.
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2818,25 +2405,35 @@ MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,LevelizeValue(GetPixelRed(image,q)),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,LevelizeValue(GetPixelGreen(image,q)),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,LevelizeValue(GetPixelBlue(image,q)),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,LevelizeValue(GetPixelBlack(image,q)),q);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-          (image->matte == MagickTrue))
-        SetPixelAlpha(image,LevelizeValue(GetPixelAlpha(image,q)),q);
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=LevelizeValue(q[i]);
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -2847,7 +2444,7 @@ MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_LevelizeImageChannel)
+        #pragma omp critical (MagickCore_LevelizeImage)
 #endif
         proceed=SetImageProgress(image,LevelizeImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2869,7 +2466,7 @@ MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  LevelImageColor() maps the given color to "black" and "white" values,
+%  LevelImageColors() maps the given color to "black" and "white" values,
 %  linearly spreading out the colors, and level values on a channel by channel
 %  bases, as per LevelImage().  The given colors allows you to specify
 %  different level ranges for each of the color channels separately.
@@ -2880,45 +2477,32 @@ MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
 %  appropriatally.  This effectivally maps a greyscale gradient into the given
 %  color gradient.
 %
-%  The format of the LevelColorsImageChannel method is:
+%  The format of the LevelImageColors method is:
 %
-%    MagickBooleanType LevelColorsImage(Image *image,
-%      const PixelInfo *black_color,
-%      const PixelInfo *white_color,const MagickBooleanType invert)
-%    MagickBooleanType LevelColorsImageChannel(Image *image,
-%      const ChannelType channel,const PixelInfo *black_color,
-%      const PixelInfo *white_color,const MagickBooleanType invert)
+%    MagickBooleanType LevelImageColors(Image *image,
+%      const PixelInfo *black_color,const PixelInfo *white_color,
+%      const MagickBooleanType invert,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o black_color: The color to map black to/from
 %
 %    o white_point: The color to map white to/from
 %
 %    o invert: if true map the colors (levelize), rather than from (level)
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
-MagickExport MagickBooleanType LevelColorsImage(Image *image,
+MagickExport MagickBooleanType LevelImageColors(Image *image,
   const PixelInfo *black_color,const PixelInfo *white_color,
-  const MagickBooleanType invert)
+  const MagickBooleanType invert,ExceptionInfo *exception)
 {
-  MagickBooleanType
-    status;
-
-  status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
-    invert);
-  return(status);
-}
+  ChannelType
+    channel_mask;
 
-MagickExport MagickBooleanType LevelColorsImageChannel(Image *image,
-  const ChannelType channel,const PixelInfo *black_color,
-  const PixelInfo *white_color,const MagickBooleanType invert)
-{
   MagickStatusType
     status;
 
@@ -2932,43 +2516,83 @@ MagickExport MagickBooleanType LevelColorsImageChannel(Image *image,
   status=MagickFalse;
   if (invert == MagickFalse)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelImageChannel(image,RedChannel,
-          black_color->red,white_color->red,(double) 1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelImageChannel(image,GreenChannel,
-          black_color->green,white_color->green,(double) 1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelImageChannel(image,BlueChannel,
-          black_color->blue,white_color->blue,(double) 1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,RedChannel);
+          status|=LevelImage(image,black_color->red,white_color->red,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,GreenChannel);
+          status|=LevelImage(image,black_color->green,white_color->green,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,BlueChannel);
+          status|=LevelImage(image,black_color->blue,white_color->blue,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
           (image->colorspace == CMYKColorspace))
-        status|=LevelImageChannel(image,BlackChannel,
-          black_color->black,white_color->black,(double) 1.0);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
+        {
+          channel_mask=SetPixelChannelMask(image,BlackChannel);
+          status|=LevelImage(image,black_color->black,white_color->black,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
           (image->matte == MagickTrue))
-        status|=LevelImageChannel(image,OpacityChannel,
-          black_color->alpha,white_color->alpha,(double) 1.0);
+        {
+          channel_mask=SetPixelChannelMask(image,AlphaChannel);
+          status|=LevelImage(image,black_color->alpha,white_color->alpha,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
     }
   else
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelizeImageChannel(image,RedChannel,
-          black_color->red,white_color->red,(double) 1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelizeImageChannel(image,GreenChannel,
-          black_color->green,white_color->green,(double) 1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        status|=LevelizeImageChannel(image,BlueChannel,
-          black_color->blue,white_color->blue,(double) 1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,RedChannel);
+          status|=LevelizeImage(image,black_color->red,white_color->red,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,GreenChannel);
+          status|=LevelizeImage(image,black_color->green,white_color->green,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+        {
+          channel_mask=SetPixelChannelMask(image,BlueChannel);
+          status|=LevelizeImage(image,black_color->blue,white_color->blue,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
           (image->colorspace == CMYKColorspace))
-        status|=LevelizeImageChannel(image,BlackChannel,
-          black_color->black,white_color->black,(double) 1.0);
-      if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
+        {
+          channel_mask=SetPixelChannelMask(image,BlackChannel);
+          status|=LevelizeImage(image,black_color->black,white_color->black,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
+      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
           (image->matte == MagickTrue))
-        status|=LevelizeImageChannel(image,OpacityChannel,
-          black_color->alpha,white_color->alpha,(double) 1.0);
+        {
+          channel_mask=SetPixelChannelMask(image,AlphaChannel);
+          status|=LevelizeImage(image,black_color->alpha,white_color->alpha,1.0,
+            exception);
+          (void) SetPixelChannelMask(image,channel_mask);
+        }
     }
   return(status == 0 ? MagickFalse : MagickTrue);
 }
@@ -2984,13 +2608,14 @@ MagickExport MagickBooleanType LevelColorsImageChannel(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  The LinearStretchImage() discards any pixels below the black point and
-%  above the white point and levels the remaining pixels.
+%  LinearStretchImage() discards any pixels below the black point and above
+%  the white point and levels the remaining pixels.
 %
 %  The format of the LinearStretchImage method is:
 %
 %      MagickBooleanType LinearStretchImage(Image *image,
-%        const double black_point,const double white_point)
+%        const double black_point,const double white_point,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3000,14 +2625,16 @@ MagickExport MagickBooleanType LevelColorsImageChannel(Image *image,
 %
 %    o white_point: the white point.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType LinearStretchImage(Image *image,
-  const double black_point,const double white_point)
+  const double black_point,const double white_point,ExceptionInfo *exception)
 {
 #define LinearStretchImageTag  "LinearStretch/Image"
 
-  ExceptionInfo
-    *exception;
+  CacheView
+    *image_view;
 
   MagickBooleanType
     status;
@@ -3035,7 +2662,7 @@ MagickExport MagickBooleanType LinearStretchImage(Image *image,
     Form histogram.
   */
   (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
-  exception=(&image->exception);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -3044,15 +2671,16 @@ MagickExport MagickBooleanType LinearStretchImage(Image *image,
     register ssize_t
       x;
 
-    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
     if (p == (const Quantum *) NULL)
       break;
-    for (x=(ssize_t) image->columns-1; x >= 0; x--)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
       histogram[ScaleQuantumToMap(GetPixelIntensity(image,p))]++;
       p+=GetPixelChannels(image);
     }
   }
+  image_view=DestroyCacheView(image_view);
   /*
     Find the histogram boundaries by locating the black and white point levels.
   */
@@ -3071,8 +2699,7 @@ MagickExport MagickBooleanType LinearStretchImage(Image *image,
       break;
   }
   histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
-  status=LevelImageChannel(image,DefaultChannels,(double) black,(double) white,
-    1.0);
+  status=LevelImage(image,(double) black,(double) white,1.0,exception);
   return(status);
 }
 \f
@@ -3095,20 +2722,22 @@ MagickExport MagickBooleanType LinearStretchImage(Image *image,
 %
 %  The format of the ModulateImage method is:
 %
-%      MagickBooleanType ModulateImage(Image *image,const char *modulate)
+%      MagickBooleanType ModulateImage(Image *image,const char *modulate,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o modulate: Define the percent change in brightness, saturation, and
-%      hue.
+%    o modulate: Define the percent change in brightness, saturation, and hue.
+%
+%    o exception: return any errors or warnings in this structure.
 %
 */
 
 static void ModulateHSB(const double percent_hue,
-  const double percent_saturation,const double percent_brightness,
-  Quantum *red,Quantum *green,Quantum *blue)
+  const double percent_saturation,const double percent_brightness,double *red,
+  double *green,double *blue)
 {
   double
     brightness,
@@ -3118,9 +2747,9 @@ static void ModulateHSB(const double percent_hue,
   /*
     Increase or decrease color brightness, saturation, or hue.
   */
-  assert(red != (Quantum *) NULL);
-  assert(green != (Quantum *) NULL);
-  assert(blue != (Quantum *) NULL);
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
   ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
   hue+=0.5*(0.01*percent_hue-1.0);
   while (hue < 0.0)
@@ -3133,8 +2762,8 @@ static void ModulateHSB(const double percent_hue,
 }
 
 static void ModulateHSL(const double percent_hue,
-  const double percent_saturation,const double percent_lightness,
-  Quantum *red,Quantum *green,Quantum *blue)
+  const double percent_saturation,const double percent_lightness,double *red,
+  double *green,double *blue)
 {
   double
     hue,
@@ -3144,9 +2773,9 @@ static void ModulateHSL(const double percent_hue,
   /*
     Increase or decrease color lightness, saturation, or hue.
   */
-  assert(red != (Quantum *) NULL);
-  assert(green != (Quantum *) NULL);
-  assert(blue != (Quantum *) NULL);
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
   ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
   hue+=0.5*(0.01*percent_hue-1.0);
   while (hue < 0.0)
@@ -3158,7 +2787,7 @@ static void ModulateHSL(const double percent_hue,
   ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
 }
 
-static void ModulateHWB(const double percent_hue,const double percent_whiteness,  const double percent_blackness,Quantum *red,Quantum *green,Quantum *blue)
+static void ModulateHWB(const double percent_hue,const double percent_whiteness,  const double percent_blackness,double *red,double *green,double *blue)
 {
   double
     blackness,
@@ -3168,9 +2797,9 @@ static void ModulateHWB(const double percent_hue,const double percent_whiteness,
   /*
     Increase or decrease color blackness, whiteness, or hue.
   */
-  assert(red != (Quantum *) NULL);
-  assert(green != (Quantum *) NULL);
-  assert(blue != (Quantum *) NULL);
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
   ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
   hue+=0.5*(0.01*percent_hue-1.0);
   while (hue < 0.0)
@@ -3182,7 +2811,8 @@ static void ModulateHWB(const double percent_hue,const double percent_whiteness,
   ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
 }
 
-MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
+MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate,
+  ExceptionInfo *exception)
 {
 #define ModulateImageTag  "Modulate/Image"
 
@@ -3200,9 +2830,6 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
     percent_hue,
     percent_saturation;
 
-  ExceptionInfo
-    *exception;
-
   GeometryInfo
     geometry_info;
 
@@ -3249,7 +2876,7 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
         Modulate colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
         switch (colorspace)
@@ -3283,14 +2910,13 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
-    Quantum
+    double
       blue,
       green,
       red;
@@ -3304,16 +2930,16 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      red=GetPixelRed(image,q);
-      green=GetPixelGreen(image,q);
-      blue=GetPixelBlue(image,q);
+      red=(double) GetPixelRed(image,q);
+      green=(double) GetPixelGreen(image,q);
+      blue=(double) GetPixelBlue(image,q);
       switch (colorspace)
       {
         case HSBColorspace:
@@ -3336,9 +2962,9 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
           break;
         }
       }
-      SetPixelRed(image,red,q);
-      SetPixelGreen(image,green,q);
-      SetPixelBlue(image,blue,q);
+      SetPixelRed(image,ClampToQuantum(red),q);
+      SetPixelGreen(image,ClampToQuantum(green),q);
+      SetPixelBlue(image,ClampToQuantum(blue),q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -3349,7 +2975,7 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ModulateImage)
+        #pragma omp critical (MagickCore_ModulateImage)
 #endif
         proceed=SetImageProgress(image,ModulateImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3374,44 +3000,28 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
 %  NegateImage() negates the colors in the reference image.  The grayscale
 %  option means that only grayscale values within the image are negated.
 %
-%  The format of the NegateImageChannel method is:
+%  The format of the NegateImage method is:
 %
 %      MagickBooleanType NegateImage(Image *image,
-%        const MagickBooleanType grayscale)
-%      MagickBooleanType NegateImageChannel(Image *image,
-%        const ChannelType channel,const MagickBooleanType grayscale)
+%        const MagickBooleanType grayscale,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o grayscale: If MagickTrue, only negate grayscale pixels within the image.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
 MagickExport MagickBooleanType NegateImage(Image *image,
-  const MagickBooleanType grayscale)
-{
-  MagickBooleanType
-    status;
-
-  status=NegateImageChannel(image,DefaultChannels,grayscale);
-  return(status);
-}
-
-MagickExport MagickBooleanType NegateImageChannel(Image *image,
-  const ChannelType channel,const MagickBooleanType grayscale)
+  const MagickBooleanType grayscale,ExceptionInfo *exception)
 {
 #define NegateImageTag  "Negate/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -3434,7 +3044,7 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
         Negate colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -3442,13 +3052,13 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
           if ((image->colormap[i].red != image->colormap[i].green) ||
               (image->colormap[i].green != image->colormap[i].blue))
             continue;
-        if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
           image->colormap[i].red=(Quantum) QuantumRange-
             image->colormap[i].red;
-        if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
           image->colormap[i].green=(Quantum) QuantumRange-
             image->colormap[i].green;
-        if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
           image->colormap[i].blue=(Quantum) QuantumRange-
             image->colormap[i].blue;
       }
@@ -3458,12 +3068,11 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
   if (grayscale != MagickFalse)
     {
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
       {
@@ -3480,30 +3089,36 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
           continue;
         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
           exception);
-        if (q == (const Quantum *) NULL)
+        if (q == (Quantum *) NULL)
           {
             status=MagickFalse;
             continue;
           }
         for (x=0; x < (ssize_t) image->columns; x++)
         {
-          if ((GetPixelRed(image,q) != GetPixelGreen(image,q)) ||
-              (GetPixelGreen(image,q) != GetPixelBlue(image,q)))
+          register ssize_t
+            i;
+
+          if ((GetPixelMask(image,q) != 0) ||
+              (IsPixelGray(image,q) != MagickFalse))
             {
               q+=GetPixelChannels(image);
               continue;
             }
-          if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-            SetPixelRed(image,QuantumRange-GetPixelRed(image,q),q);
-          if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-            SetPixelGreen(image,QuantumRange-GetPixelGreen(image,q),q);
-          if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-            SetPixelBlue(image,QuantumRange-GetPixelBlue(image,q),q);
-          if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(image,QuantumRange-GetPixelBlack(image,q),q);
-          if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-            SetPixelAlpha(image,QuantumRange-GetPixelAlpha(image,q),q);
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            PixelChannel
+              channel;
+
+            PixelTrait
+              traits;
+
+            channel=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            if ((traits & UpdatePixelTrait) == 0)
+              continue;
+            q[i]=QuantumRange-q[i];
+          }
           q+=GetPixelChannels(image);
         }
         sync=SyncCacheViewAuthenticPixels(image_view,exception);
@@ -3515,7 +3130,7 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
               proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_NegateImageChannel)
+            #pragma omp critical (MagickCore_NegateImage)
 #endif
             proceed=SetImageProgress(image,NegateImageTag,progress++,
               image->rows);
@@ -3530,7 +3145,7 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
     Negate image.
   */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3543,24 +3158,35 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,QuantumRange-GetPixelRed(image,q),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,QuantumRange-GetPixelGreen(image,q),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,QuantumRange-GetPixelBlue(image,q),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,QuantumRange-GetPixelBlack(image,q),q);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        SetPixelAlpha(image,QuantumRange-GetPixelAlpha(image,q),q);
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=QuantumRange-q[i];
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -3571,7 +3197,7 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_NegateImageChannel)
+        #pragma omp critical (MagickCore_NegateImage)
 #endif
         proceed=SetImageProgress(image,NegateImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3599,29 +3225,17 @@ MagickExport MagickBooleanType NegateImageChannel(Image *image,
 %
 %  The format of the NormalizeImage method is:
 %
-%      MagickBooleanType NormalizeImage(Image *image)
-%      MagickBooleanType NormalizeImageChannel(Image *image,
-%        const ChannelType channel)
+%      MagickBooleanType NormalizeImage(Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
+%    o exception: return any errors or warnings in this structure.
 %
 */
-
-MagickExport MagickBooleanType NormalizeImage(Image *image)
-{
-  MagickBooleanType
-    status;
-
-  status=NormalizeImageChannel(image,DefaultChannels);
-  return(status);
-}
-
-MagickExport MagickBooleanType NormalizeImageChannel(Image *image,
-  const ChannelType channel)
+MagickExport MagickBooleanType NormalizeImage(Image *image,
+  ExceptionInfo *exception)
 {
   double
     black_point,
@@ -3629,7 +3243,7 @@ MagickExport MagickBooleanType NormalizeImageChannel(Image *image,
 
   black_point=(double) image->columns*image->rows*0.0015;
   white_point=(double) image->columns*image->rows*0.9995;
-  return(ContrastStretchImageChannel(image,channel,black_point,white_point));
+  return(ContrastStretchImage(image,black_point,white_point,exception));
 }
 \f
 /*
@@ -3655,17 +3269,13 @@ MagickExport MagickBooleanType NormalizeImageChannel(Image *image,
 %  The format of the SigmoidalContrastImage method is:
 %
 %      MagickBooleanType SigmoidalContrastImage(Image *image,
-%        const MagickBooleanType sharpen,const char *levels)
-%      MagickBooleanType SigmoidalContrastImageChannel(Image *image,
-%        const ChannelType channel,const MagickBooleanType sharpen,
-%        const double contrast,const double midpoint)
+%        const MagickBooleanType sharpen,const char *levels,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o channel: the channel.
-%
 %    o sharpen: Increase or decrease image contrast.
 %
 %    o alpha: strength of the contrast, the larger the number the more
@@ -3673,42 +3283,18 @@ MagickExport MagickBooleanType NormalizeImageChannel(Image *image,
 %
 %    o beta: midpoint of the function as a color value 0 to QuantumRange.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-
 MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
-  const MagickBooleanType sharpen,const char *levels)
-{
-  GeometryInfo
-    geometry_info;
-
-  MagickBooleanType
-    status;
-
-  MagickStatusType
-    flags;
-
-  flags=ParseGeometry(levels,&geometry_info);
-  if ((flags & SigmaValue) == 0)
-    geometry_info.sigma=1.0*QuantumRange/2.0;
-  if ((flags & PercentValue) != 0)
-    geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
-  status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
-    geometry_info.rho,geometry_info.sigma);
-  return(status);
-}
-
-MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
-  const ChannelType channel,const MagickBooleanType sharpen,
-  const double contrast,const double midpoint)
+  const MagickBooleanType sharpen,const double contrast,const double midpoint,
+  ExceptionInfo *exception)
 {
 #define SigmoidalContrastImageTag  "SigmoidalContrast/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -3738,20 +3324,52 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
       image->filename);
   (void) ResetMagickMemory(sigmoidal_map,0,(MaxMap+1)*sizeof(*sigmoidal_map));
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
   for (i=0; i <= (ssize_t) MaxMap; i++)
   {
     if (sharpen != MagickFalse)
       {
+#define sigmoidal(a,b,x)  (1/(1+exp((a)*((b)-(x)))))
+#if 1
+        /* Simpilified function scaling,
+         * with better 'contrast=0' or 'flatline' handling (greyscale)
+         */
+        double
+          u0 = sigmoidal(contrast,QuantumScale*midpoint,0.0),
+          u1 = sigmoidal(contrast,QuantumScale*midpoint,1.0);
+        sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
+           (MagickRealType)(MaxMap*(
+               (sigmoidal(contrast,QuantumScale*midpoint,(double)i/MaxMap)
+                  -(u0+u1)/2.0)/(u1-u0+MagickEpsilon)+0.5)   ));
+#else
+        /* Scaled sigmoidal formula...
+             (1/(1+exp(a*(b-u))) - 1/(1+exp(a))) /
+                     (1/(1+exp(a*(b-1)))/(1+exp(a)))) */
         sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
           (MaxMap*((1.0/(1.0+exp(contrast*(midpoint/(double) QuantumRange-
           (double) i/MaxMap))))-(1.0/(1.0+exp(contrast*(midpoint/
           (double) QuantumRange)))))/((1.0/(1.0+exp(contrast*(midpoint/
           (double) QuantumRange-1.0))))-(1.0/(1.0+exp(contrast*(midpoint/
           (double) QuantumRange)))))+0.5));
+#endif
         continue;
       }
+#if 1
+    {
+      /* Inverse -- See
+         http://osdir.com/ml/video.image-magick.devel/2005-04/msg00006.html
+      */
+      double
+        min = sigmoidal(contrast,1.0,0.0),
+        max = sigmoidal(contrast,QuantumScale*midpoint,1.0),
+        xi  = min+(double)i/MaxMap*(max-min);
+      sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
+         (MagickRealType)(MaxMap*(
+             QuantumScale*midpoint-log((1-xi)/xi)/contrast) ));
+    }
+#else
+    /* expanded form of the above */
     sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
       (MaxMap*(QuantumScale*midpoint-log((1.0-(1.0/(1.0+exp(midpoint/
       (double) QuantumRange*contrast))+((double) i/MaxMap)*((1.0/
@@ -3761,6 +3379,7 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
       ((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(midpoint/
       (double) QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/
       (double) QuantumRange*contrast))))))/contrast)));
+#endif
   }
   if (image->storage_class == PseudoClass)
     {
@@ -3768,22 +3387,22 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
         Sigmoidal-contrast enhance colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
-        if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].red=ClampToQuantum(sigmoidal_map[
-            ScaleQuantumToMap(image->colormap[i].red)]);
-        if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].green=ClampToQuantum(sigmoidal_map[
-            ScaleQuantumToMap(image->colormap[i].green)]);
-        if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
-            ScaleQuantumToMap(image->colormap[i].blue)]);
-        if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-          image->colormap[i].alpha=ClampToQuantum(sigmoidal_map[
-            ScaleQuantumToMap(image->colormap[i].alpha)]);
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].red=sigmoidal_map[ScaleQuantumToMap(
+            ClampToQuantum(image->colormap[i].red))];
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].green=sigmoidal_map[ScaleQuantumToMap(
+            ClampToQuantum(image->colormap[i].green))];
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].blue=sigmoidal_map[ScaleQuantumToMap(
+            ClampToQuantum(image->colormap[i].blue))];
+        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].alpha=sigmoidal_map[ScaleQuantumToMap(
+            ClampToQuantum(image->colormap[i].alpha))];
       }
     }
   /*
@@ -3791,10 +3410,9 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3807,29 +3425,35 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
     if (status == MagickFalse)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        SetPixelRed(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
-          GetPixelRed(image,q))]),q);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        SetPixelGreen(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
-          GetPixelGreen(image,q))]),q);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        SetPixelBlue(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
-          GetPixelBlue(image,q))]),q);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
-          GetPixelBlack(image,q))]),q);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        SetPixelAlpha(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
-          GetPixelAlpha(image,q))]),q);
+      register ssize_t
+        i;
+
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(q[i])]);
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -3840,7 +3464,7 @@ MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_SigmoidalContrastImageChannel)
+        #pragma omp critical (MagickCore_SigmoidalContrastImage)
 #endif
         proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress++,
           image->rows);