]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/paint.c
(no commit message)
[imagemagick] / MagickCore / paint.c
index 44663614c98a764d4c3f239b6e2d6afc6fb6ad1f..75dc1259197ed5823328ea82e77e2eb15877ed5b 100644 (file)
 %                        Methods to Paint on an Image                         %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 July 1998                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 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  %
@@ -40,6 +40,7 @@
  Include declarations.
 */
 #include "MagickCore/studio.h"
+#include "MagickCore/channel.h"
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace-private.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/gem.h"
+#include "MagickCore/gem-private.h"
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel-accessor.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/statistic.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/thread-private.h"
 \f
 %  specified, the color value is changed for any neighbor pixel that does not
 %  match the bordercolor member of image.
 %
-%  By default target must match a particular pixel color exactly.
-%  However, in many cases two colors may differ by a small amount.  The
-%  fuzz member of image defines how much tolerance is acceptable to
-%  consider two colors as the same.  For example, set fuzz to 10 and the
-%  color red at intensities of 100 and 102 respectively are now
-%  interpreted as the same color for the purposes of the floodfill.
+%  By default target must match a particular pixel color exactly.  However,
+%  in many cases two colors may differ by a small amount.  The fuzz member of
+%  image defines how much tolerance is acceptable to consider two colors as
+%  the same.  For example, set fuzz to 10 and the color red at intensities of
+%  100 and 102 respectively are now interpreted as the same color for the
+%  purposes of the floodfill.
 %
 %  The format of the FloodfillPaintImage method is:
 %
 %      MagickBooleanType FloodfillPaintImage(Image *image,
 %        const DrawInfo *draw_info,const PixelInfo target,
 %        const ssize_t x_offset,const ssize_t y_offset,
-%        const MagickBooleanType invert)
+%        const MagickBooleanType invert,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %
 %    o invert: paint any pixel that does not match the target color.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
   const DrawInfo *draw_info,const PixelInfo *target,const ssize_t x_offset,
-  const ssize_t y_offset,const MagickBooleanType invert)
+  const ssize_t y_offset,const MagickBooleanType invert,
+  ExceptionInfo *exception)
 {
-#define MaxStacksize  (1UL << 15)
+#define MaxStacksize  131072UL
 #define PushSegmentStack(up,left,right,delta) \
 { \
   if (s >= (segment_stack+MaxStacksize)) \
@@ -126,22 +133,20 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     *floodplane_view,
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   Image
     *floodplane_image;
 
   MagickBooleanType
-    skip;
+    skip,
+    status;
+
+  MemoryInfo
+    *segment_info;
 
   PixelInfo
-    fill,
+    fill_color,
     pixel;
 
-  PixelPacket
-    fill_color;
-
   register SegmentInfo
     *s;
 
@@ -169,50 +174,57 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     return(MagickFalse);
   if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
     return(MagickFalse);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  if (image->matte == MagickFalse)
-    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  if (IsGrayColorspace(image->colorspace) != MagickFalse)
+    (void) SetImageColorspace(image,sRGBColorspace,exception);
+  if ((image->alpha_trait != BlendPixelTrait) &&
+      (draw_info->fill.alpha_trait == BlendPixelTrait))
+    (void) SetImageAlpha(image,OpaqueAlpha,exception);
   /*
     Set floodfill state.
   */
-  floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
   if (floodplane_image == (Image *) NULL)
     return(MagickFalse);
-  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
-  segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
-    sizeof(*segment_stack));
-  if (segment_stack == (SegmentInfo *) NULL)
+  floodplane_image->alpha_trait=UndefinedPixelTrait;
+  floodplane_image->colorspace=GRAYColorspace;
+  (void) QueryColorCompliance("#000",AllCompliance,
+    &floodplane_image->background_color,exception);
+  (void) SetImageBackgroundColor(floodplane_image,exception);
+  segment_info=AcquireVirtualMemory(MaxStacksize,sizeof(*segment_stack));
+  if (segment_info == (MemoryInfo *) NULL)
     {
       floodplane_image=DestroyImage(floodplane_image);
       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
         image->filename);
     }
+  segment_stack=(SegmentInfo *) GetVirtualMemoryBlob(segment_info);
   /*
     Push initial segment on stack.
   */
-  exception=(&image->exception);
+  status=MagickTrue;
   x=x_offset;
   y=y_offset;
   start=0;
   s=segment_stack;
   PushSegmentStack(y,x,x,1);
   PushSegmentStack(y+1,x,x,-1);
-  GetPixelInfo(image,&fill);
   GetPixelInfo(image,&pixel);
-  image_view=AcquireCacheView(image);
-  floodplane_view=AcquireCacheView(floodplane_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  floodplane_view=AcquireAuthenticCacheView(floodplane_image,exception);
   while (s > segment_stack)
   {
     register const Quantum
       *restrict p;
 
-    register ssize_t
-      x;
-
     register Quantum
       *restrict q;
 
+    register ssize_t
+      x;
+
     /*
       Pop segment off stack.
     */
@@ -233,12 +245,12 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     q+=x1*GetPixelChannels(floodplane_image);
     for (x=x1; x >= 0; x--)
     {
-      if (GetPixelAlpha(image,q) == TransparentAlpha)
+      if (GetPixelGray(floodplane_image,q) != 0)
         break;
-      SetPixelInfo(image,p,&pixel);
+      GetPixelInfoPixel(image,p,&pixel);
       if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
         break;
-      SetPixelAlpha(floodplane_image,TransparentAlpha,q);
+      SetPixelGray(floodplane_image,QuantumRange,q);
       p-=GetPixelChannels(image);
       q-=GetPixelChannels(floodplane_image);
     }
@@ -260,24 +272,23 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
             {
               p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
                 exception);
-              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,
-                image->columns-x,1,exception);
-              if ((p == (const Quantum *) NULL) ||
-                  (q == (Quantum *) NULL))
+              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,image->columns-
+                x,1,exception);
+              if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
                 break;
               for ( ; x < (ssize_t) image->columns; x++)
               {
-                if (GetPixelAlpha(image,q) == TransparentAlpha)
+                if (GetPixelGray(floodplane_image,q) != 0)
                   break;
-                SetPixelInfo(image,p,&pixel);
+                GetPixelInfoPixel(image,p,&pixel);
                 if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
                   break;
-                SetPixelAlpha(floodplane_image,
-                  TransparentAlpha,q);
+                SetPixelGray(floodplane_image,QuantumRange,q);
                 p+=GetPixelChannels(image);
                 q+=GetPixelChannels(floodplane_image);
               }
-              if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
+              status=SyncCacheViewAuthenticPixels(floodplane_view,exception);
+              if (status == MagickFalse)
                 break;
             }
           PushSegmentStack(y,start,x-1,offset);
@@ -292,14 +303,13 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
             exception);
           q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
             exception);
-          if ((p == (const Quantum *) NULL) ||
-              (q == (Quantum *) NULL))
+          if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
             break;
           for ( ; x <= x2; x++)
           {
-            if (GetPixelAlpha(image,q) == TransparentAlpha)
+            if (GetPixelGray(floodplane_image,q) != 0)
               break;
-            SetPixelInfo(image,p,&pixel);
+            GetPixelInfoPixel(image,p,&pixel);
             if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
               break;
             p+=GetPixelChannels(image);
@@ -314,39 +324,25 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     register const Quantum
       *restrict p;
 
-    register ssize_t
-      x;
-
     register Quantum
       *restrict q;
 
+    register ssize_t
+      x;
+
     /*
       Tile fill color onto floodplane.
     */
-    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,
-      exception);
+    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,exception);
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       break;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if (GetPixelAlpha(floodplane_image,p) != OpaqueAlpha)
+      if (GetPixelGray(floodplane_image,p) != 0)
         {
-          (void) GetFillColor(draw_info,x,y,&fill_color);
-          SetPixelInfoPacket(image,&fill_color,&fill);
-          if (image->colorspace == CMYKColorspace)
-            ConvertRGBToCMYK(&fill);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(image,ClampToQuantum(fill.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(image,ClampToQuantum(fill.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(image,ClampToQuantum(fill.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(image,ClampToQuantum(fill.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(image,ClampToQuantum(fill.alpha),q);
+          (void) GetFillColor(draw_info,x,y,&fill_color,exception);
+          SetPixelInfoPixel(image,&fill_color,q);
         }
       p+=GetPixelChannels(floodplane_image);
       q+=GetPixelChannels(image);
@@ -356,7 +352,7 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
   }
   floodplane_view=DestroyCacheView(floodplane_view);
   image_view=DestroyCacheView(image_view);
-  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
+  segment_info=RelinquishVirtualMemory(segment_info);
   floodplane_image=DestroyImage(floodplane_image);
   return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
 }
@@ -381,8 +377,8 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
 %  The format of the GradientImage method is:
 %
 %      MagickBooleanType GradientImage(Image *image,const GradientType type,
-%        const SpreadMethod method,const PixelPacket *start_color,
-%        const PixelPacket *stop_color)
+%        const SpreadMethod method,const PixelInfo *start_color,
+%        const PixelInfo *stop_color,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -396,6 +392,8 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
 %
 %    o stop_color: the stop color.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 
 static inline double MagickMax(const double x,const double y)
@@ -405,7 +403,8 @@ static inline double MagickMax(const double x,const double y)
 
 MagickExport MagickBooleanType GradientImage(Image *image,
   const GradientType type,const SpreadMethod method,
-  const PixelPacket *start_color,const PixelPacket *stop_color)
+  const PixelInfo *start_color,const PixelInfo *stop_color,
+  ExceptionInfo *exception)
 {
   DrawInfo
     *draw_info;
@@ -426,8 +425,8 @@ MagickExport MagickBooleanType GradientImage(Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(start_color != (const PixelPacket *) NULL);
-  assert(stop_color != (const PixelPacket *) NULL);
+  assert(start_color != (const PixelInfo *) NULL);
+  assert(stop_color != (const PixelInfo *) NULL);
   draw_info=AcquireDrawInfo();
   gradient=(&draw_info->gradient);
   gradient->type=type;
@@ -454,20 +453,16 @@ MagickExport MagickBooleanType GradientImage(Image *image,
     sizeof(*gradient->stops));
   for (i=0; i < (ssize_t) gradient->number_stops; i++)
     GetPixelInfo(image,&gradient->stops[i].color);
-  SetPixelInfoPacket(image,start_color,&gradient->stops[0].color);
+  gradient->stops[0].color=(*start_color);
   gradient->stops[0].offset=0.0;
-  SetPixelInfoPacket(image,stop_color,&gradient->stops[1].color);
+  gradient->stops[1].color=(*stop_color);
   gradient->stops[1].offset=1.0;
   /*
     Draw a gradient on the image.
   */
-  status=DrawGradientImage(image,draw_info);
+  (void) SetImageColorspace(image,start_color->colorspace,exception);
+  status=DrawGradientImage(image,draw_info,exception);
   draw_info=DestroyDrawInfo(draw_info);
-  if ((start_color->alpha == OpaqueAlpha) && (stop_color->alpha == OpaqueAlpha))
-    image->matte=MagickFalse;
-  if ((IsPixelPacketGray(start_color) != MagickFalse) &&
-      (IsPixelPacketGray(stop_color) != MagickFalse))
-    image->type=GrayscaleType;
   return(status);
 }
 \f
@@ -489,7 +484,7 @@ MagickExport MagickBooleanType GradientImage(Image *image,
 %  The format of the OilPaintImage method is:
 %
 %      Image *OilPaintImage(const Image *image,const double radius,
-%        ExceptionInfo *exception)
+%        const double sigma,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -497,6 +492,8 @@ MagickExport MagickBooleanType GradientImage(Image *image,
 %
 %    o radius: the radius of the circular neighborhood.
 %
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -507,7 +504,7 @@ static size_t **DestroyHistogramThreadSet(size_t **histogram)
     i;
 
   assert(histogram != (size_t **) NULL);
-  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
     if (histogram[i] != (size_t *) NULL)
       histogram[i]=(size_t *) RelinquishMagickMemory(histogram[i]);
   histogram=(size_t **) RelinquishMagickMemory(histogram);
@@ -523,16 +520,14 @@ static size_t **AcquireHistogramThreadSet(const size_t count)
     **histogram,
     number_threads;
 
-  number_threads=GetOpenMPMaximumThreads();
-  histogram=(size_t **) AcquireQuantumMemory(number_threads,
-    sizeof(*histogram));
+  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
+  histogram=(size_t **) AcquireQuantumMemory(number_threads,sizeof(*histogram));
   if (histogram == (size_t **) NULL)
     return((size_t **) NULL);
   (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
   for (i=0; i < (ssize_t) number_threads; i++)
   {
-    histogram[i]=(size_t *) AcquireQuantumMemory(count,
-      sizeof(**histogram));
+    histogram[i]=(size_t *) AcquireQuantumMemory(count,sizeof(**histogram));
     if (histogram[i] == (size_t *) NULL)
       return(DestroyHistogramThreadSet(histogram));
   }
@@ -540,7 +535,7 @@ static size_t **AcquireHistogramThreadSet(const size_t count)
 }
 
 MagickExport Image *OilPaintImage(const Image *image,const double radius,
-  ExceptionInfo *exception)
+  const double sigma,ExceptionInfo *exception)
 {
 #define NumberPaintBins  256
 #define OilPaintImageTag  "OilPaint/Image"
@@ -550,6 +545,7 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
     *paint_view;
 
   Image
+    *linear_image,
     *paint_image;
 
   MagickBooleanType
@@ -559,10 +555,11 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
     progress;
 
   size_t
-    **restrict histograms,
+    **histograms,
     width;
 
   ssize_t
+    center,
     y;
 
   /*
@@ -574,19 +571,27 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  width=GetOptimalKernelWidth2D(radius,0.5);
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  linear_image=CloneImage(image,0,0,MagickTrue,exception);
   paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
-  if (paint_image == (Image *) NULL)
-    return((Image *) NULL);
-  if (SetImageStorageClass(paint_image,DirectClass) == MagickFalse)
+  if ((linear_image == (Image *) NULL) || (paint_image == (Image *) NULL))
     {
-      InheritException(exception,&paint_image->exception);
+      if (linear_image != (Image *) NULL)
+        linear_image=DestroyImage(linear_image);
+      if (paint_image != (Image *) NULL)
+        linear_image=DestroyImage(paint_image);
+      return((Image *) NULL);
+    }
+  if (SetImageStorageClass(paint_image,DirectClass,exception) == MagickFalse)
+    {
+      linear_image=DestroyImage(linear_image);
       paint_image=DestroyImage(paint_image);
       return((Image *) NULL);
     }
   histograms=AcquireHistogramThreadSet(NumberPaintBins);
   if (histograms == (size_t **) NULL)
     {
+      linear_image=DestroyImage(linear_image);
       paint_image=DestroyImage(paint_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
     }
@@ -595,29 +600,32 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  paint_view=AcquireCacheView(paint_image);
+  center=(ssize_t) GetPixelChannels(linear_image)*(linear_image->columns+width)*
+    (width/2L)+GetPixelChannels(linear_image)*(width/2L);
+  image_view=AcquireVirtualCacheView(linear_image,exception);
+  paint_view=AcquireAuthenticCacheView(paint_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) \
+    magick_threads(linear_image,paint_image,linear_image->rows,1)
 #endif
-  for (y=0; y < (ssize_t) image->rows; y++)
+  for (y=0; y < (ssize_t) linear_image->rows; y++)
   {
     register const Quantum
       *restrict p;
 
-    register ssize_t
-      x;
-
     register Quantum
       *restrict q;
 
     register size_t
       *histogram;
 
+    register ssize_t
+      x;
+
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
-      (width/2L),image->columns+width,width,exception);
+      (width/2L),linear_image->columns+width,width,exception);
     q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
@@ -626,7 +634,7 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
         continue;
       }
     histogram=histograms[GetOpenMPThreadId()];
-    for (x=0; x < (ssize_t) image->columns; x++)
+    for (x=0; x < (ssize_t) linear_image->columns; x++)
     {
       register ssize_t
         i,
@@ -638,55 +646,63 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
       ssize_t
         j,
         k,
+        n,
         v;
 
       /*
         Assign most frequent color.
       */
-      i=0;
+      k=0;
       j=0;
       count=0;
-      (void) ResetMagickMemory(histogram,0,NumberPaintBins*sizeof(*histogram));
+      (void) ResetMagickMemory(histogram,0,NumberPaintBins* sizeof(*histogram));
       for (v=0; v < (ssize_t) width; v++)
       {
         for (u=0; u < (ssize_t) width; u++)
         {
-          k=(ssize_t) ScaleQuantumToChar(GetPixelIntensity(image,p+u+i));
-          histogram[k]++;
-          if (histogram[k] > count)
+          n=(ssize_t) ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity(
+            linear_image,p+GetPixelChannels(linear_image)*(u+k))));
+          histogram[n]++;
+          if (histogram[n] > count)
             {
-              j=i+u;
-              count=histogram[k];
+              j=k+u;
+              count=histogram[n];
             }
         }
-        i+=(ssize_t) (image->columns+width);
+        k+=(ssize_t) (linear_image->columns+width);
       }
-      SetPixelRed(paint_image,GetPixelRed(image,p+j*
-        GetPixelChannels(image)),q);
-      SetPixelGreen(paint_image,GetPixelGreen(image,p+j*
-        GetPixelChannels(image)),q);
-      SetPixelBlue(paint_image,GetPixelBlue(image,p+j*
-        GetPixelChannels(image)),q);
-      if (image->colorspace == CMYKColorspace)
-        SetPixelBlack(paint_image,GetPixelBlack(image,p+j*
-          GetPixelChannels(image)),q);
-      if (image->matte != MagickFalse)
-        SetPixelAlpha(paint_image,GetPixelAlpha(image,p+j*
-          GetPixelChannels(image)),q);
-      p+=GetPixelChannels(image);
+      for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
+      {
+        PixelChannel channel=GetPixelChannelChannel(linear_image,i);
+        PixelTrait traits=GetPixelChannelTraits(linear_image,channel);
+        PixelTrait paint_traits=GetPixelChannelTraits(paint_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (paint_traits == UndefinedPixelTrait))
+          continue;
+        if (((paint_traits & CopyPixelTrait) != 0) ||
+            (GetPixelReadMask(linear_image,p) == 0))
+          {
+            SetPixelChannel(paint_image,channel,p[center+i],q);
+            continue;
+          }
+        SetPixelChannel(paint_image,channel,p[j*GetPixelChannels(linear_image)+
+          i],q);
+      }
+      p+=GetPixelChannels(linear_image);
       q+=GetPixelChannels(paint_image);
     }
     if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
       status=MagickFalse;
-    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+    if (linear_image->progress_monitor != (MagickProgressMonitor) NULL)
       {
         MagickBooleanType
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_OilPaintImage)
+        #pragma omp critical (MagickCore_OilPaintImage)
 #endif
-        proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
+        proceed=SetImageProgress(linear_image,OilPaintImageTag,progress++,
+          linear_image->rows);
         if (proceed == MagickFalse)
           status=MagickFalse;
       }
@@ -694,6 +710,7 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
   paint_view=DestroyCacheView(paint_view);
   image_view=DestroyCacheView(image_view);
   histograms=DestroyHistogramThreadSet(histograms);
+  linear_image=DestroyImage(linear_image);
   if (status == MagickFalse)
     paint_image=DestroyImage(paint_image);
   return(paint_image);
@@ -713,17 +730,17 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
 %  OpaquePaintImage() changes any pixel that matches color with the color
 %  defined by fill.
 %
-%  By default color must match a particular pixel color exactly.  However,
-%  in many cases two colors may differ by a small amount.  Fuzz defines
-%  how much tolerance is acceptable to consider two colors as the same.
-%  For example, set fuzz to 10 and the color red at intensities of 100 and
-%  102 respectively are now interpreted as the same color.
+%  By default color must match a particular pixel color exactly.  However, in
+%  many cases two colors may differ by a small amount.  Fuzz defines how much
+%  tolerance is acceptable to consider two colors as the same.  For example,
+%  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
+%  are now interpreted as the same color.
 %
 %  The format of the OpaquePaintImage method is:
 %
 %      MagickBooleanType OpaquePaintImage(Image *image,
-%        const PixelPacket *target,const PixelPacket *fill,
-%        const MagickBooleanType invert)
+%        const PixelInfo *target,const PixelInfo *fill,
+%        const MagickBooleanType invert,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -735,18 +752,18 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
 %
 %    o invert: paint any pixel that does not match the target color.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType OpaquePaintImage(Image *image,
-  const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert)
+  const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert,
+  ExceptionInfo *exception)
 {
 #define OpaquePaintImageTag  "Opaque/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -765,34 +782,40 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
   assert(fill != (PixelInfo *) NULL);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
+      (IsPixelInfoGray(fill) == MagickFalse))
+    (void) SetImageColorspace(image,sRGBColorspace,exception);
+  if ((fill->alpha_trait == BlendPixelTrait) &&
+      (image->alpha_trait != BlendPixelTrait))
+    (void) SetImageAlpha(image,OpaqueAlpha,exception);
   /*
     Make image color opaque.
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
   GetPixelInfo(image,&zero);
-  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) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     PixelInfo
       pixel;
 
-    register ssize_t
-      x;
-
     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)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
@@ -800,21 +823,9 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
     pixel=zero;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelInfo(image,q,&pixel);
+      GetPixelInfoPixel(image,q,&pixel);
       if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
-        {
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(image,ClampToQuantum(fill->red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(image,ClampToQuantum(fill->green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(image,ClampToQuantum(fill->blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(image,ClampToQuantum(fill->black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(image,ClampToQuantum(fill->alpha),q);
-        }
+        SetPixelInfoPixel(image,fill,q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -825,7 +836,7 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_OpaquePaintImage)
+        #pragma omp critical (MagickCore_OpaquePaintImage)
 #endif
         proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
           image->rows);
@@ -851,17 +862,17 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
 %  TransparentPaintImage() changes the opacity value associated with any pixel
 %  that matches color to the value defined by opacity.
 %
-%  By default color must match a particular pixel color exactly.  However,
-%  in many cases two colors may differ by a small amount.  Fuzz defines
-%  how much tolerance is acceptable to consider two colors as the same.
-%  For example, set fuzz to 10 and the color red at intensities of 100 and
-%  102 respectively are now interpreted as the same color.
+%  By default color must match a particular pixel color exactly.  However, in
+%  many cases two colors may differ by a small amount.  Fuzz defines how much
+%  tolerance is acceptable to consider two colors as the same.  For example,
+%  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
+%  are now interpreted as the same color.
 %
 %  The format of the TransparentPaintImage method is:
 %
 %      MagickBooleanType TransparentPaintImage(Image *image,
 %        const PixelInfo *target,const Quantum opacity,
-%        const MagickBooleanType invert)
+%        const MagickBooleanType invert,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -873,19 +884,18 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
 %
 %    o invert: paint any pixel that does not match the target color.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType TransparentPaintImage(Image *image,
-  const PixelInfo *target,const Quantum opacity,
-  const MagickBooleanType invert)
+  const PixelInfo *target,const Quantum opacity,const MagickBooleanType invert,
+  ExceptionInfo *exception)
 {
 #define TransparentPaintImageTag  "Transparent/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -903,20 +913,20 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
   assert(target != (PixelInfo *) NULL);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  if (image->matte == MagickFalse)
-    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  if (image->alpha_trait != BlendPixelTrait)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   /*
     Make image color transparent.
   */
   status=MagickTrue;
   progress=0;
-  exception=(&image->exception);
   GetPixelInfo(image,&zero);
-  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) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -932,7 +942,7 @@ MagickExport MagickBooleanType TransparentPaintImage(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;
@@ -940,7 +950,7 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
     pixel=zero;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelInfo(image,q,&pixel);
+      GetPixelInfoPixel(image,q,&pixel);
       if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
         SetPixelAlpha(image,opacity,q);
       q+=GetPixelChannels(image);
@@ -953,7 +963,7 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_TransparentPaintImage)
+        #pragma omp critical (MagickCore_TransparentPaintImage)
 #endif
         proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
           image->rows);
@@ -979,18 +989,18 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
 %  TransparentPaintImageChroma() changes the opacity value associated with any
 %  pixel that matches color to the value defined by opacity.
 %
-%  As there is one fuzz value for the all the channels, the
-%  TransparentPaintImage() API is not suitable for the operations like chroma,
-%  where the tolerance for similarity of two color component (RGB) can be
-%  different, Thus we define this method take two target pixels (one
-%  low and one hight) and all the pixels of an image which are lying between
-%  these two pixels are made transparent.
+%  As there is one fuzz value for the all the channels, TransparentPaintImage()
+%  is not suitable for the operations like chroma, where the tolerance for
+%  similarity of two color component (RGB) can be different. Thus we define
+%  this method to take two target pixels (one low and one high) and all the
+%  pixels of an image which are lying between these two pixels are made
+%  transparent.
 %
-%  The format of the TransparentPaintImage method is:
+%  The format of the TransparentPaintImageChroma method is:
 %
-%      MagickBooleanType TransparentPaintImage(Image *image,
-%        const PixelInfo *low,const PixelInfo *hight,
-%        const Quantum opacity,const MagickBooleanType invert)
+%      MagickBooleanType TransparentPaintImageChroma(Image *image,
+%        const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
+%        const MagickBooleanType invert,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1004,19 +1014,18 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
 %
 %    o invert: paint any pixel that does not match the target color.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
-  const PixelInfo *low,const PixelInfo *high,
-  const Quantum opacity,const MagickBooleanType invert)
+  const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
+  const MagickBooleanType invert,ExceptionInfo *exception)
 {
 #define TransparentPaintImageTag  "Transparent/Image"
 
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -1032,19 +1041,19 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
   assert(low != (PixelInfo *) NULL);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  if (image->matte == MagickFalse)
-    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  if (image->alpha_trait != BlendPixelTrait)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   /*
     Make image color transparent.
   */
   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) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1054,16 +1063,16 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
     PixelInfo
       pixel;
 
-    register ssize_t
-      x;
-
     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)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
@@ -1071,11 +1080,11 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
     GetPixelInfo(image,&pixel);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelInfo(image,q,&pixel);
+      GetPixelInfoPixel(image,q,&pixel);
       match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
         (pixel.green >= low->green) && (pixel.green <= high->green) &&
-        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ?
-        MagickTrue : MagickFalse;
+        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ? MagickTrue :
+        MagickFalse;
       if (match != invert)
         SetPixelAlpha(image,opacity,q);
       q+=GetPixelChannels(image);
@@ -1088,7 +1097,7 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_TransparentPaintImageChroma)
+        #pragma omp critical (MagickCore_TransparentPaintImageChroma)
 #endif
         proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
           image->rows);