]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/quantize.c
https://github.com/ImageMagick/ImageMagick/issues/1584
[imagemagick] / MagickCore / quantize.c
index ae13eb497934cd0721b3497a59b4c1365a5ffa71..76995a4433ecd15e846703065049de1978f0686f 100644 (file)
 %                              July 1992                                      %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2019 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                                            %
 %                                                                             %
-%    https://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,          %
   Include declarations.
 */
 #include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
 #include "MagickCore/attribute.h"
 #include "MagickCore/cache-view.h"
 #include "MagickCore/color.h"
 #include "MagickCore/quantum-private.h"
 #include "MagickCore/resource_.h"
 #include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
 #include "MagickCore/thread-private.h"
 \f
 /*
@@ -532,7 +534,7 @@ static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
       status=MagickTrue;
       image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(static,4) shared(status) \
+      #pragma omp parallel for schedule(static) shared(status) \
         magick_number_threads(image,image,image->rows,1)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
@@ -629,9 +631,6 @@ static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
             MagickBooleanType
               proceed;
 
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-            #pragma omp critical (MagickCore_AssignImageColors)
-#endif
             proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
               image->rows);
             if (proceed == MagickFalse)
@@ -892,7 +891,7 @@ static MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
           ClampPixel(pixel.alpha);
       else
         node_info->total_color.alpha+=count*QuantumScale*
-          ClampPixel(OpaqueAlpha);
+          ClampPixel((MagickRealType) OpaqueAlpha);
       p+=count*GetPixelChannels(image);
     }
     if (cube_info->colors > cube_info->maximum_colors)
@@ -999,7 +998,7 @@ static MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
           ClampPixel(pixel.alpha);
       else
         node_info->total_color.alpha+=count*QuantumScale*
-          ClampPixel(OpaqueAlpha);
+          ClampPixel((MagickRealType) OpaqueAlpha);
       p+=count*GetPixelChannels(image);
     }
     proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
@@ -1490,6 +1489,12 @@ static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info,
   CacheView
     *image_view;
 
+  const char
+    *artifact;
+
+  double
+    amount;
+
   DoublePixelPacket
     **pixels;
 
@@ -1506,6 +1511,10 @@ static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info,
   if (pixels == (DoublePixelPacket **) NULL)
     return(MagickFalse);
   status=MagickTrue;
+  amount=1.0;
+  artifact=GetImageArtifact(image,"dither:diffusion-amount");
+  if (artifact != (const char *) NULL)
+    amount=StringToDoubleInterval(artifact,1.0);
   image_view=AcquireAuthenticCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1559,11 +1568,11 @@ static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info,
       AssociateAlphaPixel(image,&cube,q+u*GetPixelChannels(image),&pixel);
       if (x > 0)
         {
-          pixel.red+=7*current[u-v].red/16;
-          pixel.green+=7*current[u-v].green/16;
-          pixel.blue+=7*current[u-v].blue/16;
+          pixel.red+=7.0*amount*current[u-v].red/16;
+          pixel.green+=7.0*amount*current[u-v].green/16;
+          pixel.blue+=7.0*amount*current[u-v].blue/16;
           if (cube.associate_alpha != MagickFalse)
-            pixel.alpha+=7*current[u-v].alpha/16;
+            pixel.alpha+=7.0*amount*current[u-v].alpha/16;
         }
       if (y > 0)
         {
@@ -1575,18 +1584,18 @@ static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info,
               if (cube.associate_alpha != MagickFalse)
                 pixel.alpha+=previous[u+v].alpha/16;
             }
-          pixel.red+=5*previous[u].red/16;
-          pixel.green+=5*previous[u].green/16;
-          pixel.blue+=5*previous[u].blue/16;
+          pixel.red+=5.0*amount*previous[u].red/16;
+          pixel.green+=5.0*amount*previous[u].green/16;
+          pixel.blue+=5.0*amount*previous[u].blue/16;
           if (cube.associate_alpha != MagickFalse)
-            pixel.alpha+=5*previous[u].alpha/16;
+            pixel.alpha+=5.0*amount*previous[u].alpha/16;
           if (x > 0)
             {
-              pixel.red+=3*previous[u-v].red/16;
-              pixel.green+=3*previous[u-v].green/16;
-              pixel.blue+=3*previous[u-v].blue/16;
+              pixel.red+=3.0*amount*previous[u-v].red/16;
+              pixel.green+=3.0*amount*previous[u-v].green/16;
+              pixel.blue+=3.0*amount*previous[u-v].blue/16;
               if (cube.associate_alpha != MagickFalse)
-                pixel.alpha+=3*previous[u-v].alpha/16;
+                pixel.alpha+=3.0*amount*previous[u-v].alpha/16;
             }
         }
       pixel.red=(double) ClampPixel(pixel.red);
@@ -1941,8 +1950,7 @@ static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info,
   /*
     Distribute quantization error along a Hilbert curve.
   */
-  (void) memset(cube_info->error,0,ErrorQueueLength*
-    sizeof(*cube_info->error));
+  (void) memset(cube_info->error,0,ErrorQueueLength*sizeof(*cube_info->error));
   cube_info->x=0;
   cube_info->y=0;
   i=MagickMax((ssize_t) image->columns,(ssize_t) image->rows);
@@ -2044,8 +2052,7 @@ static CubeInfo *GetCubeInfo(const QuantizeInfo *quantize_info,
   /*
     Initialize color cache.
   */
-  (void) memset(cube_info->cache,(-1),sizeof(*cube_info->cache)*
-    length);
+  (void) memset(cube_info->cache,(-1),sizeof(*cube_info->cache)*length);
   /*
     Distribute weights along a curve of exponential decay.
   */
@@ -2192,10 +2199,8 @@ MagickExport MagickBooleanType GetImageQuantizeError(Image *image,
     mean_error,
     mean_error_per_pixel;
 
-  size_t
-    index;
-
   ssize_t
+    index,
     y;
 
   assert(image != (Image *) NULL);
@@ -2226,7 +2231,7 @@ MagickExport MagickBooleanType GetImageQuantizeError(Image *image,
       break;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      index=GetPixelIndex(image,p);
+      index=(ssize_t) GetPixelIndex(image,p);
       if (image->alpha_trait == BlendPixelTrait)
         {
           alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
@@ -2342,8 +2347,8 @@ MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
   const DitherMethod dither_method,ExceptionInfo *exception)
 {
 #define PosterizeImageTag  "Posterize/Image"
-#define PosterizePixel(pixel) (Quantum) (QuantumRange*(MagickRound( \
-  QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))
+#define PosterizePixel(pixel) ClampToQuantum((MagickRealType) QuantumRange*( \
+  MagickRound(QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))
 
   CacheView
     *image_view;
@@ -2371,7 +2376,7 @@ MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
   assert(exception->signature == MagickCoreSignature);
   if (image->storage_class == PseudoClass)
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-    #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    #pragma omp parallel for schedule(static) shared(progress,status) \
       magick_number_threads(image,image,image->colors,1)
 #endif
     for (i=0; i < (ssize_t) image->colors; i++)
@@ -2399,7 +2404,7 @@ MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
   progress=0;
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+  #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++)
@@ -2442,10 +2447,10 @@ MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-        #pragma omp critical (MagickCore_PosterizeImage)
+        #pragma omp atomic
 #endif
-        proceed=SetImageProgress(image,PosterizeImageTag,progress++,
-          image->rows);
+        progress++;
+        proceed=SetImageProgress(image,PosterizeImageTag,progress,image->rows);
         if (proceed == MagickFalse)
           status=MagickFalse;
       }
@@ -2667,7 +2672,8 @@ MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
       if (SetImageGray(image,exception) != MagickFalse)
         (void) SetGrayscaleImage(image,exception);
     }
-  if ((image->storage_class == PseudoClass) &&
+  if ((quantize_info->dither_method == NoDitherMethod) &&
+      (image->storage_class == PseudoClass) &&
       (image->colors <= maximum_colors))
     {
       if ((quantize_info->colorspace != UndefinedColorspace) &&
@@ -2706,13 +2712,10 @@ MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
   if (status != MagickFalse)
     {
       /*
-        Reduce the number of colors in the image if it contains more than the
-        maximum, otherwise we can disable dithering to improve the performance.
+        Reduce the number of colors in the image.
       */
       if (cube_info->colors > cube_info->maximum_colors)
         ReduceImageColors(image,cube_info);
-      else
-        cube_info->quantize_info->dither_method=NoDitherMethod;
       status=AssignImageColors(image,cube_info,exception);
     }
   DestroyCubeInfo(cube_info);
@@ -3287,6 +3290,10 @@ static int IntensityCompare(const void *x,const void *y)
   color_2=(PixelInfo *) y;
   intensity=GetPixelInfoIntensity((const Image *) NULL,color_1)-
     GetPixelInfoIntensity((const Image *) NULL,color_2);
+  if (intensity > (double) INT_MAX)
+    intensity=(double) INT_MAX;
+  if (intensity < (double) INT_MIN)
+    intensity=(double) INT_MIN;
   return((int) intensity);
 }
 
@@ -3309,6 +3316,9 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
   register ssize_t
     i;
 
+  size_t
+    extent;
+
   ssize_t
     *colormap_index,
     j,
@@ -3318,19 +3328,15 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
   assert(image->signature == MagickCoreSignature);
   if (image->type != GrayscaleType)
     (void) TransformImageColorspace(image,GRAYColorspace,exception);
-  if (image->storage_class == PseudoClass)
-    colormap_index=(ssize_t *) AcquireQuantumMemory(image->colors,
-      sizeof(*colormap_index));
-  else
-    colormap_index=(ssize_t *) AcquireQuantumMemory(MaxColormapSize,
-      sizeof(*colormap_index));
+  extent=MagickMax(image->colors+1,MagickMax(MaxColormapSize,MaxMap+1));
+  colormap_index=(ssize_t *) AcquireQuantumMemory(extent,
+    sizeof(*colormap_index));
   if (colormap_index == (ssize_t *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   if (image->storage_class != PseudoClass)
     {
-      (void) memset(colormap_index,(-1),MaxColormapSize*
-        sizeof(*colormap_index));
+      (void) memset(colormap_index,(-1),extent*sizeof(*colormap_index));
       if (AcquireImageColormap(image,MaxColormapSize,exception) == MagickFalse)
         {
           colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
@@ -3341,7 +3347,7 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
       status=MagickTrue;
       image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(static,4) shared(status) \
+      #pragma omp parallel for schedule(static) shared(status) \
         magick_number_threads(image,image,image->rows,1)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
@@ -3392,6 +3398,7 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
       }
       image_view=DestroyCacheView(image_view);
     }
+  (void) memset(colormap_index,0,extent*sizeof(*colormap_index));
   for (i=0; i < (ssize_t) image->colors; i++)
     image->colormap[i].alpha=(double) i;
   qsort((void *) image->colormap,image->colors,sizeof(PixelInfo),
@@ -3420,7 +3427,7 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
   status=MagickTrue;
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status) \
+  #pragma omp parallel for schedule(static) shared(status) \
     magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)