]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/paint.c
https://github.com/ImageMagick/ImageMagick/issues/1336
[imagemagick] / MagickCore / paint.c
index 7f2e33e9caa477ee3acc6c854d2c407213d4e10d..609e53d59daa662f458f0a80526eb45ffd1139af 100644 (file)
 %                                 July 1998                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2018 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  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://imagemagick.org/script/license.php                               %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -114,7 +114,7 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
   const ssize_t y_offset,const MagickBooleanType invert,
   ExceptionInfo *exception)
 {
-#define MaxStacksize  262144UL
+#define MaxStacksize  524288UL
 #define PushSegmentStack(up,left,right,delta) \
 { \
   if (s >= (segment_stack+MaxStacksize)) \
@@ -186,7 +186,7 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
   /*
     Set floodfill state.
   */
-  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+  floodplane_image=CloneImage(image,0,0,MagickTrue,
     exception);
   if (floodplane_image == (Image *) NULL)
     return(MagickFalse);
@@ -217,10 +217,10 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
   while (s > segment_stack)
   {
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -320,17 +320,13 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     } while (x <= x2);
   }
   status=MagickTrue;
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(floodplane_image,image,floodplane_image->rows,1)
-#endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -351,7 +347,7 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
     {
       if (GetPixelGray(floodplane_image,p) != 0)
         {
-          (void) GetFillColor(draw_info,x,y,&fill_color,exception);
+          GetFillColor(draw_info,x,y,&fill_color,exception);
           SetPixelViaPixelInfo(image,&fill_color,q);
         }
       p+=GetPixelChannels(floodplane_image);
@@ -405,17 +401,6 @@ MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-
-static inline double MagickRound(double x)
-{
-  /*
-    Round the fraction to nearest integer.
-  */
-  if ((x-floor(x)) < (ceil(x)-x))
-    return(floor(x));
-  return(ceil(x));
-}
-
 MagickExport MagickBooleanType GradientImage(Image *image,
   const GradientType type,const SpreadMethod method,const StopInfo *stops,
   const size_t number_stops,ExceptionInfo *exception)
@@ -449,8 +434,8 @@ MagickExport MagickBooleanType GradientImage(Image *image,
   artifact=GetImageArtifact(image,"gradient:bounding-box");
   if (artifact != (const char *) NULL)
     (void) ParseAbsoluteGeometry(artifact,&gradient->bounding_box);
-  gradient->gradient_vector.x2=(double) image->columns-1.0;
-  gradient->gradient_vector.y2=(double) image->rows-1.0;
+  gradient->gradient_vector.x2=(double) image->columns-1;
+  gradient->gradient_vector.y2=(double) image->rows-1;
   artifact=GetImageArtifact(image,"gradient:direction");
   if (artifact != (const char *) NULL)
     {
@@ -463,8 +448,8 @@ MagickExport MagickBooleanType GradientImage(Image *image,
       {
         case NorthWestGravity:
         {
-          gradient->gradient_vector.x1=(double) image->columns-1.0;
-          gradient->gradient_vector.y1=(double) image->rows-1.0;
+          gradient->gradient_vector.x1=(double) image->columns-1;
+          gradient->gradient_vector.y1=(double) image->rows-1;
           gradient->gradient_vector.x2=0.0;
           gradient->gradient_vector.y2=0.0;
           break;
@@ -472,7 +457,7 @@ MagickExport MagickBooleanType GradientImage(Image *image,
         case NorthGravity:
         {
           gradient->gradient_vector.x1=0.0;
-          gradient->gradient_vector.y1=(double) image->rows-1.0;
+          gradient->gradient_vector.y1=(double) image->rows-1;
           gradient->gradient_vector.x2=0.0;
           gradient->gradient_vector.y2=0.0;
           break;
@@ -480,14 +465,14 @@ MagickExport MagickBooleanType GradientImage(Image *image,
         case NorthEastGravity:
         {
           gradient->gradient_vector.x1=0.0;
-          gradient->gradient_vector.y1=(double) image->rows-1.0;
-          gradient->gradient_vector.x2=(double) image->columns-1.0;
+          gradient->gradient_vector.y1=(double) image->rows-1;
+          gradient->gradient_vector.x2=(double) image->columns-1;
           gradient->gradient_vector.y2=0.0;
           break;
         }
         case WestGravity:
         {
-          gradient->gradient_vector.x1=(double) image->columns-1.0;
+          gradient->gradient_vector.x1=(double) image->columns-1;
           gradient->gradient_vector.y1=0.0;
           gradient->gradient_vector.x2=0.0;
           gradient->gradient_vector.y2=0.0;
@@ -497,16 +482,16 @@ MagickExport MagickBooleanType GradientImage(Image *image,
         {
           gradient->gradient_vector.x1=0.0;
           gradient->gradient_vector.y1=0.0;
-          gradient->gradient_vector.x2=(double) image->columns-1.0;
+          gradient->gradient_vector.x2=(double) image->columns-1;
           gradient->gradient_vector.y2=0.0;
           break;
         }
         case SouthWestGravity:
         {
-          gradient->gradient_vector.x1=(double) image->columns-1.0;
+          gradient->gradient_vector.x1=(double) image->columns-1;
           gradient->gradient_vector.y1=0.0;
           gradient->gradient_vector.x2=0.0;
-          gradient->gradient_vector.y2=(double) image->rows-1.0;
+          gradient->gradient_vector.y2=(double) image->rows-1;
           break;
         }
         case SouthGravity:
@@ -514,15 +499,15 @@ MagickExport MagickBooleanType GradientImage(Image *image,
           gradient->gradient_vector.x1=0.0;
           gradient->gradient_vector.y1=0.0;
           gradient->gradient_vector.x2=0.0;
-          gradient->gradient_vector.y2=(double) image->columns-1.0;
+          gradient->gradient_vector.y2=(double) image->columns-1;
           break;
         }
         case SouthEastGravity:
         {
           gradient->gradient_vector.x1=0.0;
           gradient->gradient_vector.y1=0.0;
-          gradient->gradient_vector.x2=(double) image->columns-1.0;
-          gradient->gradient_vector.y2=(double) image->rows-1.0;
+          gradient->gradient_vector.x2=(double) image->columns-1;
+          gradient->gradient_vector.y2=(double) image->rows-1;
           break;
         }
         default:
@@ -531,33 +516,15 @@ MagickExport MagickBooleanType GradientImage(Image *image,
     }
   artifact=GetImageArtifact(image,"gradient:angle");
   if (artifact != (const char *) NULL)
-    {
-      double
-        angle,
-        cosine,
-        distance,
-        sine;
-
-      angle=StringToDouble(artifact,(char **) NULL);
-      cosine=cos(MagickPI*angle/180.0);
-      sine=sin(MagickPI*angle/180.0);
-      distance=fabs(sine*image->columns)+fabs(cosine*image->rows);
-      gradient->gradient_vector.x1=MagickRound(0.5*(image->columns-cosine*
-        distance));
-      gradient->gradient_vector.y1=MagickRound(0.5*(image->rows-sine*
-        distance));
-      gradient->gradient_vector.x2=MagickRound(0.5*(image->columns+cosine*
-        distance));
-      gradient->gradient_vector.y2=MagickRound(0.5*(image->rows+sine*
-        distance));
-    }
+    gradient->angle=StringToDouble(artifact,(char **) NULL);
   artifact=GetImageArtifact(image,"gradient:vector");
   if (artifact != (const char *) NULL)
     (void) sscanf(artifact,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",
       &gradient->gradient_vector.x1,&gradient->gradient_vector.y1,
       &gradient->gradient_vector.x2,&gradient->gradient_vector.y2);
-  if ((GetImageArtifact(image,"gradient:direction") == (const char *) NULL) &&
-      (GetImageArtifact(image,"gradient:angle") == (const char *) NULL) &&
+  if ((GetImageArtifact(image,"gradient:angle") == (const char *) NULL) &&
+      (GetImageArtifact(image,"gradient:direction") == (const char *) NULL) &&
+      (GetImageArtifact(image,"gradient:extent") == (const char *) NULL) &&
       (GetImageArtifact(image,"gradient:vector") == (const char *) NULL))
     if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
       gradient->gradient_vector.x2=0.0;
@@ -567,9 +534,63 @@ MagickExport MagickBooleanType GradientImage(Image *image,
   if (artifact != (const char *) NULL)
     (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->center.x,
       &gradient->center.y);
-  gradient->radii.x=MagickMax(gradient->center.x,gradient->center.y);
-  gradient->radii.y=MagickMax(gradient->center.x,gradient->center.y);
-  artifact=GetImageArtifact(image,"gradient:radius");
+  artifact=GetImageArtifact(image,"gradient:angle");
+  if ((type == LinearGradient) && (artifact != (const char *) NULL))
+    {
+      double
+        sine,
+        cosine,
+        distance;
+
+      /*
+        Reference https://drafts.csswg.org/css-images-3/#linear-gradients.
+      */
+      sine=sin((double) DegreesToRadians(gradient->angle-90.0));
+      cosine=cos((double) DegreesToRadians(gradient->angle-90.0));
+      distance=fabs((double) (image->columns-1.0)*cosine)+
+        fabs((double) (image->rows-1.0)*sine);
+      gradient->gradient_vector.x1=0.5*((image->columns-1.0)-distance*cosine);
+      gradient->gradient_vector.y1=0.5*((image->rows-1.0)-distance*sine);
+      gradient->gradient_vector.x2=0.5*((image->columns-1.0)+distance*cosine);
+      gradient->gradient_vector.y2=0.5*((image->rows-1.0)+distance*sine);
+    }
+  gradient->radii.x=(double) MagickMax((image->columns-1.0),(image->rows-1.0))/
+    2.0;
+  gradient->radii.y=gradient->radii.x;
+  artifact=GetImageArtifact(image,"gradient:extent");
+  if (artifact != (const char *) NULL)
+    {
+      if (LocaleCompare(artifact,"Circle") == 0)
+        {
+          gradient->radii.x=(double) MagickMax((image->columns-1.0),
+            (image->rows-1.0))/2.0;
+          gradient->radii.y=gradient->radii.x;
+        }
+      if (LocaleCompare(artifact,"Diagonal") == 0)
+        {
+          gradient->radii.x=(double) (sqrt((double) (image->columns-1.0)*
+            (image->columns-1.0)+(image->rows-1.0)*(image->rows-1.0)))/2.0;
+          gradient->radii.y=gradient->radii.x;
+        }
+      if (LocaleCompare(artifact,"Ellipse") == 0)
+        {
+          gradient->radii.x=(double) (image->columns-1.0)/2.0;
+          gradient->radii.y=(double) (image->rows-1.0)/2.0;
+        }
+      if (LocaleCompare(artifact,"Maximum") == 0)
+        {
+          gradient->radii.x=(double) MagickMax((image->columns-1.0),
+            (image->rows-1.0))/2.0;
+          gradient->radii.y=gradient->radii.x;
+        }
+      if (LocaleCompare(artifact,"Minimum") == 0)
+        {
+          gradient->radii.x=(double) (MagickMin((image->columns-1.0),
+            (image->rows-1.0)))/2.0;
+          gradient->radii.y=gradient->radii.x;
+        }
+    }
+  artifact=GetImageArtifact(image,"gradient:radii");
   if (artifact != (const char *) NULL)
     (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->radii.x,
       &gradient->radii.y);
@@ -584,7 +605,7 @@ MagickExport MagickBooleanType GradientImage(Image *image,
   if (gradient->stops == (StopInfo *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
-  (void) CopyMagickMemory(gradient->stops,stops,(size_t) number_stops*
+  (void) memcpy(gradient->stops,stops,(size_t) number_stops*
     sizeof(*stops));
   /*
     Draw a gradient on the image.
@@ -652,7 +673,7 @@ static size_t **AcquireHistogramThreadSet(const size_t count)
   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));
+  (void) memset(histogram,0,number_threads*sizeof(*histogram));
   for (i=0; i < (ssize_t) number_threads; i++)
   {
     histogram[i]=(size_t *) AcquireQuantumMemory(count,sizeof(**histogram));
@@ -701,7 +722,7 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
   assert(exception->signature == MagickCoreSignature);
   width=GetOptimalKernelWidth2D(radius,sigma);
   linear_image=CloneImage(image,0,0,MagickTrue,exception);
-  paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  paint_image=CloneImage(image,0,0,MagickTrue,exception);
   if ((linear_image == (Image *) NULL) || (paint_image == (Image *) NULL))
     {
       if (linear_image != (Image *) NULL)
@@ -733,16 +754,16 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
   image_view=AcquireVirtualCacheView(linear_image,exception);
   paint_view=AcquireAuthenticCacheView(paint_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status) \
-    magick_threads(linear_image,paint_image,linear_image->rows,1)
+  #pragma omp parallel for schedule(static) shared(progress,status) \
+    magick_number_threads(linear_image,paint_image,linear_image->rows,1)
 #endif
   for (y=0; y < (ssize_t) linear_image->rows; y++)
   {
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register size_t
       *histogram;
@@ -783,7 +804,7 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
       k=0;
       j=0;
       count=0;
-      (void) ResetMagickMemory(histogram,0,NumberPaintBins* sizeof(*histogram));
+      (void) memset(histogram,0,NumberPaintBins* sizeof(*histogram));
       for (v=0; v < (ssize_t) width; v++)
       {
         for (u=0; u < (ssize_t) width; u++)
@@ -801,14 +822,13 @@ MagickExport Image *OilPaintImage(const Image *image,const double radius,
       }
       for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
       {
-        PixelChannel channel=GetPixelChannelChannel(linear_image,i);
-        PixelTrait traits=GetPixelChannelTraits(linear_image,channel);
+        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))
+        if ((paint_traits & CopyPixelTrait) != 0)
           {
             SetPixelChannel(paint_image,channel,p[center+i],q);
             continue;
@@ -924,8 +944,8 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
   GetPixelInfo(image,&zero);
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status) \
-    magick_threads(image,image,image->rows,1)
+  #pragma omp parallel for schedule(static) shared(progress,status) \
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -933,7 +953,7 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
       pixel;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -951,7 +971,26 @@ MagickExport MagickBooleanType OpaquePaintImage(Image *image,
     {
       GetPixelInfoPixel(image,q,&pixel);
       if (IsFuzzyEquivalencePixelInfo(&pixel,&conform_target) != invert)
-        SetPixelViaPixelInfo(image,&conform_fill,q);
+        {
+          PixelTrait
+            traits;
+
+          traits=GetPixelChannelTraits(image,RedPixelChannel);
+          if ((traits & UpdatePixelTrait) != 0)
+            SetPixelRed(image,(Quantum) conform_fill.red,q);
+          traits=GetPixelChannelTraits(image,GreenPixelChannel);
+          if ((traits & UpdatePixelTrait) != 0)
+            SetPixelGreen(image,(Quantum) conform_fill.green,q);
+          traits=GetPixelChannelTraits(image,BluePixelChannel);
+          if ((traits & UpdatePixelTrait) != 0)
+            SetPixelBlue(image,(Quantum) conform_fill.blue,q);
+          traits=GetPixelChannelTraits(image,BlackPixelChannel);
+          if ((traits & UpdatePixelTrait) != 0)
+            SetPixelBlack(image,(Quantum) conform_fill.black,q);
+          traits=GetPixelChannelTraits(image,AlphaPixelChannel);
+          if ((traits & UpdatePixelTrait) != 0)
+            SetPixelAlpha(image,(Quantum) conform_fill.alpha,q);
+        }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -1051,8 +1090,8 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
   GetPixelInfo(image,&zero);
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status) \
-    magick_threads(image,image,image->rows,1)
+  #pragma omp parallel for schedule(static) shared(progress,status) \
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1063,7 +1102,7 @@ MagickExport MagickBooleanType TransparentPaintImage(Image *image,
       x;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     if (status == MagickFalse)
       continue;
@@ -1178,8 +1217,8 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
   progress=0;
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status) \
-    magick_threads(image,image,image->rows,1)
+  #pragma omp parallel for schedule(static) shared(progress,status) \
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1190,7 +1229,7 @@ MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
       pixel;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;