]> granicus.if.org Git - imagemagick/commitdiff
Improved performance of QuantizeImage method when the number of colors don't need...
authordirk <dirk@git.imagemagick.org>
Sat, 27 Jun 2015 20:26:03 +0000 (20:26 +0000)
committerdirk <dirk@git.imagemagick.org>
Sat, 27 Jun 2015 20:26:03 +0000 (20:26 +0000)
MagickCore/quantize.c

index 772ef9b322cfb42d3a89b8e56cf4923636f8375a..b3a1cce557b2362e06fa875a97a58734b5dde588 100644 (file)
@@ -492,14 +492,9 @@ static inline size_t ColorToNodeId(const CubeInfo *cube_info,
   return(id);
 }
 
-static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
-  ExceptionInfo *exception)
+static inline MagickBooleanType PreAssignImageColors(Image *image,
+  CubeInfo *cube_info,ExceptionInfo *exception)
 {
-#define AssignImageTag  "Assign/Image"
-
-  ssize_t
-    y;
-
   /*
     Allocate image colormap.
   */
@@ -509,14 +504,61 @@ static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
       cube_info->quantize_info->colorspace,exception);
   else
     if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
-      (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
+      (void) TransformImageColorspace((Image *) image,sRGBColorspace,
+         exception);
   if (AcquireImageColormap(image,cube_info->colors,exception) == MagickFalse)
-    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-      image->filename);
+    return(MagickFalse);
   image->colors=0;
   cube_info->transparent_pixels=0;
   cube_info->transparent_index=(-1);
   (void) DefineImageColormap(image,cube_info,cube_info->root);
+  return(MagickTrue);
+}
+
+static inline void PostAssignImageColors(Image *image,CubeInfo *cube_info,
+  ExceptionInfo *exception)
+{
+  if (cube_info->quantize_info->measure_error != MagickFalse)
+    (void) GetImageQuantizeError(image,exception);
+  if ((cube_info->quantize_info->number_colors == 2) &&
+      (cube_info->quantize_info->colorspace == GRAYColorspace))
+    {
+      double
+        intensity;
+
+      register PixelInfo
+        *restrict q;
+
+      register ssize_t
+        i;
+
+      /*
+        Monochrome image.
+      */
+      q=image->colormap;
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        intensity=(double) (GetPixelInfoLuma(q) < (QuantumRange/2.0) ? 0 :
+          QuantumRange);
+        q->red=intensity;
+        q->green=q->red;
+        q->blue=q->red;
+        q++;
+      }
+    }
+}
+
+static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
+  ExceptionInfo *exception)
+{
+#define AssignImageTag  "Assign/Image"
+
+  ssize_t
+    y;
+
+  if (PreAssignImageColors(image,cube_info,exception) == MagickFalse)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
   /*
     Create a reduced color image.
   */
@@ -641,34 +683,7 @@ static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
       }
       image_view=DestroyCacheView(image_view);
     }
-  if (cube_info->quantize_info->measure_error != MagickFalse)
-    (void) GetImageQuantizeError(image,exception);
-  if ((cube_info->quantize_info->number_colors == 2) &&
-      (cube_info->quantize_info->colorspace == GRAYColorspace))
-    {
-      double
-        intensity;
-
-      register PixelInfo
-        *restrict q;
-
-      register ssize_t
-        i;
-
-      /*
-        Monochrome image.
-      */
-      q=image->colormap;
-      for (i=0; i < (ssize_t) image->colors; i++)
-      {
-        intensity=(double) (GetPixelInfoLuma(q) < (QuantumRange/2.0) ? 0 :
-          QuantumRange);
-        q->red=intensity;
-        q->green=q->red;
-        q->blue=q->red;
-        q++;
-      }
-    }
+  PostAssignImageColors(image,cube_info,exception);
   (void) SyncImage(image,exception);
   if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
       (cube_info->quantize_info->colorspace != CMYKColorspace))
@@ -2640,6 +2655,59 @@ static void PruneToCubeDepth(const Image *image,CubeInfo *cube_info,
 %
 */
 
+static MagickBooleanType DirectToPseudoClassImage(Image *image,
+  CubeInfo *cube_info,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  if (cube_info->colors > cube_info->maximum_colors)
+    return(MagickFalse);
+  if (PreAssignImageColors(image,cube_info,exception) == MagickFalse)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+     magick_threads(image,image,image->rows,1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      continue;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if (IsPixelEquivalent(image,q,&image->colormap[i]) == MagickFalse)
+          continue;
+        SetPixelIndex(image,(Quantum) i,q);
+        break;
+      }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image->storage_class=PseudoClass;
+  PostAssignImageColors(image,cube_info,exception);
+  return(status);
+}
+
 static MagickBooleanType DirectToColormapImage(Image *image,
   ExceptionInfo *exception)
 {
@@ -2776,8 +2844,12 @@ MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
       /*
         Reduce the number of colors in the image.
       */
-      ReduceImageColors(image,cube_info);
-      status=AssignImageColors(image,cube_info,exception);
+      status=DirectToPseudoClassImage(image,cube_info,exception);
+      if (status == MagickFalse)
+      {
+        ReduceImageColors(image,cube_info);
+        status=AssignImageColors(image,cube_info,exception);
+      }
     }
   DestroyCubeInfo(cube_info);
   return(status);