]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/enhance.c
(no commit message)
[imagemagick] / MagickCore / enhance.c
index 6f5b50ce08dadc1b57e38cf6606e43cab53bb5f4..bf1817f97f5cd0e2188746db1bbb017734438477 100644 (file)
@@ -129,17 +129,20 @@ MagickExport MagickBooleanType AutoGammaImage(Image *image,
   status=MagickTrue;
   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
+    ChannelType
+      channel_mask;
+
     PixelTrait
       traits;
 
     traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
     if ((traits & UpdatePixelTrait) == 0)
       continue;
-    PushPixelChannelMap(image,(ChannelType) i);
+    channel_mask=SetPixelChannelMask(image,(ChannelType) i);
     status=GetImageMean(image,&mean,&sans,exception);
     gamma=log(mean*QuantumScale)/log_mean;
     status&=LevelImage(image,0.0,(double) QuantumRange,gamma,exception);
-    PopPixelChannelMap(image);
+    (void) SetPixelChannelMask(image,channel_mask);
     if (status == MagickFalse)
       break;
   }
@@ -215,8 +218,8 @@ MagickExport MagickBooleanType BrightnessContrastImage(Image *image,
 
   double
     alpha,
-    intercept,
     coefficients[2],
+    intercept,
     slope;
 
   MagickBooleanType
@@ -288,11 +291,6 @@ MagickExport MagickBooleanType BrightnessContrastImage(Image *image,
 MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
   ExceptionInfo *exception)
 {
-#define ClampAlphaPixelChannel(pixel) ClampToQuantum((pixel)->alpha)
-#define ClampBlackPixelChannel(pixel) ClampToQuantum((pixel)->black)
-#define ClampBluePixelChannel(pixel) ClampToQuantum((pixel)->blue)
-#define ClampGreenPixelChannel(pixel) ClampToQuantum((pixel)->green)
-#define ClampRedPixelChannel(pixel) ClampToQuantum((pixel)->red)
 #define ClutImageTag  "Clut/Image"
 
   CacheView
@@ -826,7 +824,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
 %  The format of the ContrastImage method is:
 %
 %      MagickBooleanType ContrastImage(Image *image,
-%        const MagickBooleanType sharpen)
+%        const MagickBooleanType sharpen,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -834,6 +832,8 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
 %
 %    o sharpen: Increase or decrease image contrast.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 
 static void Contrast(const int sign,Quantum *red,Quantum *green,Quantum *blue)
@@ -864,16 +864,13 @@ static void Contrast(const int sign,Quantum *red,Quantum *green,Quantum *blue)
 }
 
 MagickExport MagickBooleanType ContrastImage(Image *image,
-  const MagickBooleanType sharpen)
+  const MagickBooleanType sharpen,ExceptionInfo *exception)
 {
 #define ContrastImageTag  "Contrast/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   int
     sign;
 
@@ -908,7 +905,6 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
   image_view=AcquireCacheView(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
@@ -985,7 +981,7 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
 %  The format of the ContrastStretchImage method is:
 %
 %      MagickBooleanType ContrastStretchImage(Image *image,
-%        const char *levels)
+%        const char *levels,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -998,9 +994,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 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"
@@ -1008,23 +1006,17 @@ MagickExport MagickBooleanType ContrastStretchImage(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;
@@ -1039,20 +1031,32 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  histogram=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*histogram));
-  stretch_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
-    sizeof(*stretch_map));
-  if ((histogram == (PixelInfo *) NULL) ||
-      (stretch_map == (PixelInfo *) NULL))
-    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-      image->filename);
+  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=(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));
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
+    sizeof(*histogram));
   image_view=AcquireCacheView(image);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1072,248 +1076,133 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelRed(image,p))].red++;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelGreen(image,p))].green++;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelBlue(image,p))].blue++;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        histogram[ScaleQuantumToMap(GetPixelBlack(image,p))].black++;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        histogram[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha++;
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelTrait
+          traits;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        histogram[GetPixelChannels(image)*ScaleQuantumToMap(p[i])+i]++;
+      }
       p+=GetPixelChannels(image);
     }
   }
   /*
     Find the histogram boundaries by locating the black/white levels.
   */
-  black.red=0.0;
-  white.red=MaxRange(QuantumRange);
-  if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 0)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (i=0; i < (ssize_t) GetPixelChannels(image); 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) & UpdatePixelTrait) != 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));
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
 #endif
-  for (i=0; i <= (ssize_t) MaxMap; i++)
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
-    if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 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) & UpdatePixelTrait) != 0) || (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 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)
 #endif
-      for (i=0; i < (ssize_t) image->colors; i++)
+      for (j=0; j < (ssize_t) image->colors; j++)
       {
         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
           {
-            if (black.red != white.red)
+            i=GetPixelChannelMapChannel(image,RedPixelChannel);
+            if (black[i] != white[i])
               image->colormap[i].red=ClampToQuantum(stretch_map[
-                ScaleQuantumToMap(image->colormap[i].red)].red);
+                GetPixelChannels(image)*ScaleQuantumToMap(
+                image->colormap[i].red)]+i);
           }
         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[i].red=ClampToQuantum(stretch_map[
+                GetPixelChannels(image)*ScaleQuantumToMap(
+                image->colormap[i].red)]+i);
           }
         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[i].red=ClampToQuantum(stretch_map[
+                GetPixelChannels(image)*ScaleQuantumToMap(
+                image->colormap[i].red)]+i);
           }
         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[i].red=ClampToQuantum(stretch_map[
+                GetPixelChannels(image)*ScaleQuantumToMap(
+                image->colormap[i].red)]+i);
           }
       }
     }
   /*
-    Stretch image.
+    Stretch-contrast image.
   */
   status=MagickTrue;
   progress=0;
@@ -1338,37 +1227,21 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        {
-          if (black.red != white.red)
-            SetPixelRed(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelRed(image,q))].red),q);
-        }
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        {
-          if (black.green != white.green)
-            SetPixelGreen(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelGreen(image,q))].green),q);
-        }
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        {
-          if (black.blue != white.blue)
-            SetPixelBlue(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelBlue(image,q))].blue),q);
-        }
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        {
-          if (black.black != white.black)
-            SetPixelBlack(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelBlack(image,q))].black),q);
-        }
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        {
-          if (black.alpha != white.alpha)
-            SetPixelAlpha(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
-              GetPixelAlpha(image,q))].alpha),q);
-        }
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelTrait
+          traits;
+
+        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        if (black[i] != white[i])
+          q[i]=ClampToQuantum(stretch_map[GetPixelChannels(image)*
+            ScaleQuantumToMap(q[i])+i]);
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -1388,7 +1261,9 @@ MagickExport MagickBooleanType ContrastStretchImage(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
@@ -2569,6 +2444,9 @@ MagickExport MagickBooleanType LevelImageColors(Image *image,
   const PixelInfo *black_color,const PixelInfo *white_color,
   const MagickBooleanType invert)
 {
+  ChannelType
+    channel_mask;
+
   MagickStatusType
     status;
 
@@ -2584,78 +2462,78 @@ MagickExport MagickBooleanType LevelImageColors(Image *image,
     {
       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,RedChannel);
+          channel_mask=SetPixelChannelMask(image,RedChannel);
           status|=LevelImage(image,black_color->red,white_color->red,1.0,
             &image->exception);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,GreenChannel);
+          channel_mask=SetPixelChannelMask(image,GreenChannel);
           status|=LevelImage(image,black_color->green,white_color->green,1.0,
             &image->exception);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,BlueChannel);
+          channel_mask=SetPixelChannelMask(image,BlueChannel);
           status|=LevelImage(image,black_color->blue,white_color->blue,1.0,
             &image->exception);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
           (image->colorspace == CMYKColorspace))
         {
-          PushPixelChannelMap(image,BlackChannel);
+          channel_mask=SetPixelChannelMask(image,BlackChannel);
           status|=LevelImage(image,black_color->black,white_color->black,1.0,
             &image->exception);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
           (image->matte == MagickTrue))
         {
-          PushPixelChannelMap(image,AlphaChannel);
+          channel_mask=SetPixelChannelMask(image,AlphaChannel);
           status|=LevelImage(image,black_color->alpha,white_color->alpha,1.0,
             &image->exception);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
     }
   else
     {
       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,RedChannel);
+          channel_mask=SetPixelChannelMask(image,RedChannel);
           status|=LevelizeImage(image,black_color->red,white_color->red,1.0);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,GreenChannel);
+          channel_mask=SetPixelChannelMask(image,GreenChannel);
           status|=LevelizeImage(image,black_color->green,white_color->green,
             1.0);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
         {
-          PushPixelChannelMap(image,BlueChannel);
+          channel_mask=SetPixelChannelMask(image,BlueChannel);
           status|=LevelizeImage(image,black_color->blue,white_color->blue,1.0);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
           (image->colorspace == CMYKColorspace))
         {
-          PushPixelChannelMap(image,BlackChannel);
+          channel_mask=SetPixelChannelMask(image,BlackChannel);
           status|=LevelizeImage(image,black_color->black,white_color->black,
             1.0);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
           (image->matte == MagickTrue))
         {
-          PushPixelChannelMap(image,AlphaChannel);
+          channel_mask=SetPixelChannelMask(image,AlphaChannel);
           status|=LevelizeImage(image,black_color->alpha,white_color->alpha,
             1.0);
-          PopPixelChannelMap(image);
+          (void) SetPixelChannelMask(image,channel_mask);
         }
     }
   return(status == 0 ? MagickFalse : MagickTrue);
@@ -3269,14 +3147,17 @@ MagickExport MagickBooleanType NegateImage(Image *image,
 %
 %  The format of the NormalizeImage method is:
 %
-%      MagickBooleanType NormalizeImage(Image *image)
+%      MagickBooleanType NormalizeImage(Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-MagickExport MagickBooleanType NormalizeImage(Image *image)
+MagickExport MagickBooleanType NormalizeImage(Image *image,
+  ExceptionInfo *exception)
 {
   double
     black_point,
@@ -3284,7 +3165,7 @@ MagickExport MagickBooleanType NormalizeImage(Image *image)
 
   black_point=(double) image->columns*image->rows*0.0015;
   white_point=(double) image->columns*image->rows*0.9995;
-  return(ContrastStretchImage(image,black_point,white_point));
+  return(ContrastStretchImage(image,black_point,white_point,exception));
 }
 \f
 /*