quantize.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %           QQQ   U   U   AAA   N   N  TTTTT  IIIII   ZZZZZ  EEEEE            %
00007 %          Q   Q  U   U  A   A  NN  N    T      I        ZZ  E                %
00008 %          Q   Q  U   U  AAAAA  N N N    T      I      ZZZ   EEEEE            %
00009 %          Q  QQ  U   U  A   A  N  NN    T      I     ZZ     E                %
00010 %           QQQQ   UUU   A   A  N   N    T    IIIII   ZZZZZ  EEEEE            %
00011 %                                                                             %
00012 %                                                                             %
00013 %    MagickCore Methods to Reduce the Number of Unique Colors in an Image     %
00014 %                                                                             %
00015 %                           Software Design                                   %
00016 %                             John Cristy                                     %
00017 %                              July 1992                                      %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %  Realism in computer graphics typically requires using 24 bits/pixel to
00037 %  generate an image.  Yet many graphic display devices do not contain the
00038 %  amount of memory necessary to match the spatial and color resolution of
00039 %  the human eye.  The Quantize methods takes a 24 bit image and reduces
00040 %  the number of colors so it can be displayed on raster device with less
00041 %  bits per pixel.  In most instances, the quantized image closely
00042 %  resembles the original reference image.
00043 %
00044 %  A reduction of colors in an image is also desirable for image
00045 %  transmission and real-time animation.
00046 %
00047 %  QuantizeImage() takes a standard RGB or monochrome images and quantizes
00048 %  them down to some fixed number of colors.
00049 %
00050 %  For purposes of color allocation, an image is a set of n pixels, where
00051 %  each pixel is a point in RGB space.  RGB space is a 3-dimensional
00052 %  vector space, and each pixel, Pi,  is defined by an ordered triple of
00053 %  red, green, and blue coordinates, (Ri, Gi, Bi).
00054 %
00055 %  Each primary color component (red, green, or blue) represents an
00056 %  intensity which varies linearly from 0 to a maximum value, Cmax, which
00057 %  corresponds to full saturation of that color.  Color allocation is
00058 %  defined over a domain consisting of the cube in RGB space with opposite
00059 %  vertices at (0,0,0) and (Cmax, Cmax, Cmax).  QUANTIZE requires Cmax =
00060 %  255.
00061 %
00062 %  The algorithm maps this domain onto a tree in which each node
00063 %  represents a cube within that domain.  In the following discussion
00064 %  these cubes are defined by the coordinate of two opposite vertices:
00065 %  The vertex nearest the origin in RGB space and the vertex farthest from
00066 %  the origin.
00067 %
00068 %  The tree's root node represents the entire domain, (0,0,0) through
00069 %  (Cmax,Cmax,Cmax).  Each lower level in the tree is generated by
00070 %  subdividing one node's cube into eight smaller cubes of equal size.
00071 %  This corresponds to bisecting the parent cube with planes passing
00072 %  through the midpoints of each edge.
00073 %
00074 %  The basic algorithm operates in three phases: Classification,
00075 %  Reduction, and Assignment.  Classification builds a color description
00076 %  tree for the image.  Reduction collapses the tree until the number it
00077 %  represents, at most, the number of colors desired in the output image.
00078 %  Assignment defines the output image's color map and sets each pixel's
00079 %  color by restorage_class in the reduced tree.  Our goal is to minimize
00080 %  the numerical discrepancies between the original colors and quantized
00081 %  colors (quantization error).
00082 %
00083 %  Classification begins by initializing a color description tree of
00084 %  sufficient depth to represent each possible input color in a leaf.
00085 %  However, it is impractical to generate a fully-formed color description
00086 %  tree in the storage_class phase for realistic values of Cmax.  If
00087 %  colors components in the input image are quantized to k-bit precision,
00088 %  so that Cmax= 2k-1, the tree would need k levels below the root node to
00089 %  allow representing each possible input color in a leaf.  This becomes
00090 %  prohibitive because the tree's total number of nodes is 1 +
00091 %  sum(i=1, k, 8k).
00092 %
00093 %  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
00094 %  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
00095 %  Initializes data structures for nodes only as they are needed;  (2)
00096 %  Chooses a maximum depth for the tree as a function of the desired
00097 %  number of colors in the output image (currently log2(colormap size)).
00098 %
00099 %  For each pixel in the input image, storage_class scans downward from
00100 %  the root of the color description tree.  At each level of the tree it
00101 %  identifies the single node which represents a cube in RGB space
00102 %  containing the pixel's color.  It updates the following data for each
00103 %  such node:
00104 %
00105 %    n1: Number of pixels whose color is contained in the RGB cube which
00106 %    this node represents;
00107 %
00108 %    n2: Number of pixels whose color is not represented in a node at
00109 %    lower depth in the tree;  initially,  n2 = 0 for all nodes except
00110 %    leaves of the tree.
00111 %
00112 %    Sr, Sg, Sb: Sums of the red, green, and blue component values for all
00113 %    pixels not classified at a lower depth. The combination of these sums
00114 %    and n2  will ultimately characterize the mean color of a set of
00115 %    pixels represented by this node.
00116 %
00117 %    E: the distance squared in RGB space between each pixel contained
00118 %    within a node and the nodes' center.  This represents the
00119 %    quantization error for a node.
00120 %
00121 %  Reduction repeatedly prunes the tree until the number of nodes with n2
00122 %  > 0 is less than or equal to the maximum number of colors allowed in
00123 %  the output image.  On any given iteration over the tree, it selects
00124 %  those nodes whose E count is minimal for pruning and merges their color
00125 %  statistics upward. It uses a pruning threshold, Ep, to govern node
00126 %  selection as follows:
00127 %
00128 %    Ep = 0
00129 %    while number of nodes with (n2 > 0) > required maximum number of colors
00130 %      prune all nodes such that E <= Ep
00131 %      Set Ep to minimum E in remaining nodes
00132 %
00133 %  This has the effect of minimizing any quantization error when merging
00134 %  two nodes together.
00135 %
00136 %  When a node to be pruned has offspring, the pruning procedure invokes
00137 %  itself recursively in order to prune the tree from the leaves upward.
00138 %  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
00139 %  corresponding data in that node's parent.  This retains the pruned
00140 %  node's color characteristics for later averaging.
00141 %
00142 %  For each node, n2 pixels exist for which that node represents the
00143 %  smallest volume in RGB space containing those pixel's colors.  When n2
00144 %  > 0 the node will uniquely define a color in the output image. At the
00145 %  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
00146 %  the tree which represent colors present in the input image.
00147 %
00148 %  The other pixel count, n1, indicates the total number of colors within
00149 %  the cubic volume which the node represents.  This includes n1 - n2
00150 %  pixels whose colors should be defined by nodes at a lower level in the
00151 %  tree.
00152 %
00153 %  Assignment generates the output image from the pruned tree.  The output
00154 %  image consists of two parts: (1)  A color map, which is an array of
00155 %  color descriptions (RGB triples) for each color present in the output
00156 %  image;  (2)  A pixel array, which represents each pixel as an index
00157 %  into the color map array.
00158 %
00159 %  First, the assignment phase makes one pass over the pruned color
00160 %  description tree to establish the image's color map.  For each node
00161 %  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
00162 %  color of all pixels that classify no lower than this node.  Each of
00163 %  these colors becomes an entry in the color map.
00164 %
00165 %  Finally,  the assignment phase reclassifies each pixel in the pruned
00166 %  tree to identify the deepest node containing the pixel's color.  The
00167 %  pixel's value in the pixel array becomes the index of this node's mean
00168 %  color in the color map.
00169 %
00170 %  This method is based on a similar algorithm written by Paul Raveling.
00171 %
00172 */
00173 
00174 /*
00175   Include declarations.
00176 */
00177 #include "magick/studio.h"
00178 #include "magick/cache-view.h"
00179 #include "magick/color.h"
00180 #include "magick/color-private.h"
00181 #include "magick/colorspace.h"
00182 #include "magick/enhance.h"
00183 #include "magick/exception.h"
00184 #include "magick/exception-private.h"
00185 #include "magick/histogram.h"
00186 #include "magick/image.h"
00187 #include "magick/image-private.h"
00188 #include "magick/list.h"
00189 #include "magick/memory_.h"
00190 #include "magick/monitor.h"
00191 #include "magick/monitor-private.h"
00192 #include "magick/option.h"
00193 #include "magick/pixel-private.h"
00194 #include "magick/quantize.h"
00195 #include "magick/quantum.h"
00196 #include "magick/string_.h"
00197 
00198 /*
00199   Define declarations.
00200 */
00201 #define CacheShift  2
00202 #define ErrorQueueLength  16
00203 #define MaxNodes  266817
00204 #define MaxTreeDepth  8
00205 #define NodesInAList  1920
00206 
00207 /*
00208   Typdef declarations.
00209 */
00210 typedef struct _RealPixelPacket
00211 {
00212   MagickRealType
00213     red,
00214     green,
00215     blue,
00216     opacity;
00217 } RealPixelPacket;
00218 
00219 typedef struct _NodeInfo
00220 {
00221   struct _NodeInfo
00222     *parent,
00223     *child[16];
00224 
00225   MagickSizeType
00226     number_unique;
00227 
00228   RealPixelPacket
00229     total_color;
00230 
00231   MagickRealType
00232     quantize_error;
00233 
00234   unsigned long
00235     color_number,
00236     id,
00237     level;
00238 } NodeInfo;
00239 
00240 typedef struct _Nodes
00241 {
00242   NodeInfo
00243     *nodes;
00244 
00245   struct _Nodes
00246     *next;
00247 } Nodes;
00248 
00249 typedef struct _CubeInfo
00250 {
00251   NodeInfo
00252     *root;
00253 
00254   unsigned long
00255     colors,
00256     maximum_colors;
00257 
00258   long
00259     transparent_index;
00260 
00261   MagickSizeType
00262     transparent_pixels;
00263 
00264   RealPixelPacket
00265     target;
00266 
00267   MagickRealType
00268     distance,
00269     pruning_threshold,
00270     next_threshold;
00271 
00272   unsigned long
00273     nodes,
00274     free_nodes,
00275     color_number;
00276 
00277   NodeInfo
00278     *next_node;
00279 
00280   Nodes
00281     *node_queue;
00282 
00283   long
00284     *cache;
00285 
00286   RealPixelPacket
00287     error[ErrorQueueLength];
00288 
00289   MagickRealType
00290     weights[ErrorQueueLength];
00291 
00292   QuantizeInfo
00293     *quantize_info;
00294 
00295   MagickBooleanType
00296     associate_alpha;
00297 
00298   long
00299     x,
00300     y;
00301 
00302   unsigned long
00303     depth;
00304 
00305   MagickOffsetType
00306     offset;
00307 
00308   MagickSizeType
00309     span;
00310 } CubeInfo;
00311 
00312 /*
00313   Method prototypes.
00314 */
00315 static CubeInfo
00316   *GetCubeInfo(const QuantizeInfo *,const unsigned long,const unsigned long);
00317 
00318 static NodeInfo
00319   *GetNodeInfo(CubeInfo *,const unsigned long,const unsigned long,NodeInfo *);
00320 
00321 static MagickBooleanType
00322   AssignImageColors(Image *,CubeInfo *),
00323   ClassifyImageColors(CubeInfo *,const Image *,ExceptionInfo *),
00324   DitherImage(Image *,CubeInfo *),
00325   SetGrayscaleImage(Image *);
00326 
00327 static unsigned long
00328   DefineImageColormap(Image *,CubeInfo *,NodeInfo *);
00329 
00330 static void
00331   ClosestColor(const Image *,CubeInfo *,const NodeInfo *),
00332   DestroyCubeInfo(CubeInfo *),
00333   PruneLevel(const Image *,CubeInfo *,const NodeInfo *),
00334   PruneToCubeDepth(const Image *,CubeInfo *,const NodeInfo *),
00335   ReduceImageColors(const Image *,CubeInfo *);
00336 
00337 /*
00338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00339 %                                                                             %
00340 %                                                                             %
00341 %                                                                             %
00342 %   A c q u i r e Q u a n t i z e I n f o                                     %
00343 %                                                                             %
00344 %                                                                             %
00345 %                                                                             %
00346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00347 %
00348 %  AcquireQuantizeInfo() allocates the QuantizeInfo structure.
00349 %
00350 %  The format of the AcquireQuantizeInfo method is:
00351 %
00352 %      QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
00353 %
00354 %  A description of each parameter follows:
00355 %
00356 %    o image_info: the image info.
00357 %
00358 */
00359 MagickExport QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
00360 {
00361   QuantizeInfo
00362     *quantize_info;
00363 
00364   quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
00365   if (quantize_info == (QuantizeInfo *) NULL)
00366     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00367   GetQuantizeInfo(quantize_info);
00368   if (image_info != (ImageInfo *) NULL)
00369     {
00370       const char
00371         *option;
00372 
00373       quantize_info->dither=image_info->dither;
00374       option=GetImageOption(image_info,"dither");
00375       if (option != (const char *) NULL)
00376         quantize_info->dither_method=(DitherMethod) ParseMagickOption(
00377           MagickDitherOptions,MagickFalse,option);
00378       quantize_info->measure_error=image_info->verbose;
00379     }
00380   return(quantize_info);
00381 }
00382 
00383 /*
00384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00385 %                                                                             %
00386 %                                                                             %
00387 %                                                                             %
00388 +   A s s i g n I m a g e C o l o r s                                         %
00389 %                                                                             %
00390 %                                                                             %
00391 %                                                                             %
00392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00393 %
00394 %  AssignImageColors() generates the output image from the pruned tree.  The
00395 %  output image consists of two parts: (1)  A color map, which is an array
00396 %  of color descriptions (RGB triples) for each color present in the
00397 %  output image;  (2)  A pixel array, which represents each pixel as an
00398 %  index into the color map array.
00399 %
00400 %  First, the assignment phase makes one pass over the pruned color
00401 %  description tree to establish the image's color map.  For each node
00402 %  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
00403 %  color of all pixels that classify no lower than this node.  Each of
00404 %  these colors becomes an entry in the color map.
00405 %
00406 %  Finally,  the assignment phase reclassifies each pixel in the pruned
00407 %  tree to identify the deepest node containing the pixel's color.  The
00408 %  pixel's value in the pixel array becomes the index of this node's mean
00409 %  color in the color map.
00410 %
00411 %  The format of the AssignImageColors() method is:
00412 %
00413 %      MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
00414 %
00415 %  A description of each parameter follows.
00416 %
00417 %    o image: the image.
00418 %
00419 %    o cube_info: A pointer to the Cube structure.
00420 %
00421 */
00422 
00423 static inline void AssociateAlphaPixel(const CubeInfo *cube_info,
00424   const PixelPacket *pixel,RealPixelPacket *alpha_pixel)
00425 {
00426   MagickRealType
00427     alpha;
00428 
00429   if ((cube_info->associate_alpha == MagickFalse) ||
00430       (pixel->opacity == OpaqueOpacity))
00431     {
00432       alpha_pixel->red=(MagickRealType) pixel->red;
00433       alpha_pixel->green=(MagickRealType) pixel->green;
00434       alpha_pixel->blue=(MagickRealType) pixel->blue;
00435       alpha_pixel->opacity=(MagickRealType) pixel->opacity;
00436       return;
00437     }
00438   alpha=(MagickRealType) (QuantumScale*(QuantumRange-pixel->opacity));
00439   alpha_pixel->red=alpha*pixel->red;
00440   alpha_pixel->green=alpha*pixel->green;
00441   alpha_pixel->blue=alpha*pixel->blue;
00442   alpha_pixel->opacity=(MagickRealType) pixel->opacity;
00443 }
00444 
00445 static inline Quantum ClipToQuantum(const MagickRealType value)
00446 {
00447   if (value <= 0.0)
00448     return((Quantum) 0);
00449   if (value >= QuantumRange)
00450     return((Quantum) QuantumRange);
00451   return((Quantum) (value+0.5));
00452 }
00453 
00454 static inline unsigned long ColorToNodeId(const CubeInfo *cube_info,
00455   const RealPixelPacket *pixel,unsigned long index)
00456 {
00457   unsigned long
00458     id;
00459 
00460   id=(unsigned long) (
00461     ((ScaleQuantumToChar(ClipToQuantum(pixel->red)) >> index) & 0x1) |
00462     ((ScaleQuantumToChar(ClipToQuantum(pixel->green)) >> index) & 0x1) << 1 |
00463     ((ScaleQuantumToChar(ClipToQuantum(pixel->blue)) >> index) & 0x1) << 2);
00464   if (cube_info->associate_alpha != MagickFalse)
00465     id|=((ScaleQuantumToChar(ClipToQuantum(pixel->opacity)) >> index) & 0x1)
00466       << 3;
00467   return(id);
00468 }
00469 
00470 static inline MagickBooleanType IsSameColor(const Image *image,
00471   const PixelPacket *p,const PixelPacket *q)
00472 {
00473   if ((p->red != q->red) || (p->green != q->green) || (p->blue != q->blue))
00474     return(MagickFalse);
00475   if ((image->matte != MagickFalse) && (p->opacity != q->opacity))
00476     return(MagickFalse);
00477   return(MagickTrue);
00478 }
00479 
00480 static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
00481 {
00482 #define AssignImageTag  "Assign/Image"
00483 
00484   long
00485     y;
00486 
00487   MagickBooleanType
00488     proceed;
00489 
00490   RealPixelPacket
00491     pixel;
00492 
00493   register long
00494     i,
00495     x;
00496 
00497   register const NodeInfo
00498     *node_info;
00499 
00500   ssize_t
00501     count;
00502 
00503   unsigned long
00504     id,
00505     index;
00506 
00507   /*
00508     Allocate image colormap.
00509   */
00510   if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
00511       (cube_info->quantize_info->colorspace != CMYKColorspace))
00512     (void) TransformImageColorspace((Image *) image,
00513       cube_info->quantize_info->colorspace);
00514   else
00515     if ((image->colorspace != GRAYColorspace) &&
00516         (image->colorspace != RGBColorspace) &&
00517         (image->colorspace != CMYColorspace))
00518       (void) TransformImageColorspace((Image *) image,RGBColorspace);
00519   if (AcquireImageColormap(image,cube_info->colors) == MagickFalse)
00520     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00521       image->filename);
00522   image->colors=0;
00523   cube_info->transparent_pixels=0;
00524   cube_info->transparent_index=(-1);
00525   (void) DefineImageColormap(image,cube_info,cube_info->root);
00526   /*
00527     Create a reduced color image.
00528   */
00529   if ((cube_info->quantize_info->dither != MagickFalse) &&
00530       (cube_info->quantize_info->dither_method != NoDitherMethod))
00531     (void) DitherImage(image,cube_info);
00532   else
00533     {
00534       ExceptionInfo
00535         *exception;
00536 
00537       CacheView
00538         *image_view;
00539 
00540       exception=(&image->exception);
00541       image_view=AcquireCacheView(image);
00542       for (y=0; y < (long) image->rows; y++)
00543       {
00544         register IndexPacket
00545           *__restrict indexes;
00546 
00547         register PixelPacket
00548           *__restrict q;
00549 
00550         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00551           exception);
00552         if (q == (PixelPacket *) NULL)
00553           break;
00554         indexes=GetCacheViewAuthenticIndexQueue(image_view);
00555         for (x=0; x < (long) image->columns; x+=count)
00556         {
00557           /*
00558             Identify the deepest node containing the pixel's color.
00559           */
00560           for (count=1; (x+count) < (long) image->columns; count++)
00561             if (IsSameColor(image,q,q+count) == MagickFalse)
00562               break;
00563           AssociateAlphaPixel(cube_info,q,&pixel);
00564           node_info=cube_info->root;
00565           for (index=MaxTreeDepth-1; (long) index > 0; index--)
00566           {
00567             id=ColorToNodeId(cube_info,&pixel,index);
00568             if (node_info->child[id] == (NodeInfo *) NULL)
00569               break;
00570             node_info=node_info->child[id];
00571           }
00572           /*
00573             Find closest color among siblings and their children.
00574           */
00575           cube_info->target=pixel;
00576           cube_info->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
00577             (QuantumRange+1.0)+1.0);
00578           ClosestColor(image,cube_info,node_info->parent);
00579           index=cube_info->color_number;
00580           for (i=0; i < (long) count; i++)
00581           {
00582             if (image->storage_class == PseudoClass)
00583               indexes[x+i]=(IndexPacket) index;
00584             if (cube_info->quantize_info->measure_error == MagickFalse)
00585               {
00586                 q->red=image->colormap[index].red;
00587                 q->green=image->colormap[index].green;
00588                 q->blue=image->colormap[index].blue;
00589                 if (cube_info->associate_alpha != MagickFalse)
00590                   q->opacity=image->colormap[index].opacity;
00591               }
00592             q++;
00593           }
00594         }
00595         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00596           break;
00597         proceed=SetImageProgress(image,AssignImageTag,y,image->rows);
00598         if (proceed == MagickFalse)
00599           break;
00600       }
00601       image_view=DestroyCacheView(image_view);
00602     }
00603   if (cube_info->quantize_info->measure_error != MagickFalse)
00604     (void) GetImageQuantizeError(image);
00605   if ((cube_info->quantize_info->number_colors == 2) &&
00606       (cube_info->quantize_info->colorspace == GRAYColorspace))
00607     {
00608       Quantum
00609         intensity;
00610 
00611       register PixelPacket
00612         *__restrict q;
00613 
00614       /*
00615         Monochrome image.
00616       */
00617       q=image->colormap;
00618       for (i=0; i < (long) image->colors; i++)
00619       {
00620         intensity=(Quantum) (PixelIntensity(q) < ((MagickRealType)
00621           QuantumRange/2.0) ? 0 : QuantumRange);
00622         q->red=intensity;
00623         q->green=intensity;
00624         q->blue=intensity;
00625         q++;
00626       }
00627     }
00628   (void) SyncImage(image);
00629   if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
00630       (cube_info->quantize_info->colorspace != CMYKColorspace))
00631     (void) TransformImageColorspace((Image *) image,RGBColorspace);
00632   return(MagickTrue);
00633 }
00634 
00635 /*
00636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00637 %                                                                             %
00638 %                                                                             %
00639 %                                                                             %
00640 +   C l a s s i f y I m a g e C o l o r s                                     %
00641 %                                                                             %
00642 %                                                                             %
00643 %                                                                             %
00644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00645 %
00646 %  ClassifyImageColors() begins by initializing a color description tree
00647 %  of sufficient depth to represent each possible input color in a leaf.
00648 %  However, it is impractical to generate a fully-formed color
00649 %  description tree in the storage_class phase for realistic values of
00650 %  Cmax.  If colors components in the input image are quantized to k-bit
00651 %  precision, so that Cmax= 2k-1, the tree would need k levels below the
00652 %  root node to allow representing each possible input color in a leaf.
00653 %  This becomes prohibitive because the tree's total number of nodes is
00654 %  1 + sum(i=1,k,8k).
00655 %
00656 %  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
00657 %  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
00658 %  Initializes data structures for nodes only as they are needed;  (2)
00659 %  Chooses a maximum depth for the tree as a function of the desired
00660 %  number of colors in the output image (currently log2(colormap size)).
00661 %
00662 %  For each pixel in the input image, storage_class scans downward from
00663 %  the root of the color description tree.  At each level of the tree it
00664 %  identifies the single node which represents a cube in RGB space
00665 %  containing It updates the following data for each such node:
00666 %
00667 %    n1 : Number of pixels whose color is contained in the RGB cube
00668 %    which this node represents;
00669 %
00670 %    n2 : Number of pixels whose color is not represented in a node at
00671 %    lower depth in the tree;  initially,  n2 = 0 for all nodes except
00672 %    leaves of the tree.
00673 %
00674 %    Sr, Sg, Sb : Sums of the red, green, and blue component values for
00675 %    all pixels not classified at a lower depth. The combination of
00676 %    these sums and n2  will ultimately characterize the mean color of a
00677 %    set of pixels represented by this node.
00678 %
00679 %    E: the distance squared in RGB space between each pixel contained
00680 %    within a node and the nodes' center.  This represents the quantization
00681 %    error for a node.
00682 %
00683 %  The format of the ClassifyImageColors() method is:
00684 %
00685 %      MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
00686 %        const Image *image,ExceptionInfo *exception)
00687 %
00688 %  A description of each parameter follows.
00689 %
00690 %    o cube_info: A pointer to the Cube structure.
00691 %
00692 %    o image: the image.
00693 %
00694 */
00695 
00696 static inline void SetAssociatedAlpha(const Image *image,CubeInfo *cube_info)
00697 {
00698   MagickBooleanType
00699     associate_alpha;
00700 
00701   associate_alpha=image->matte;
00702   if (cube_info->quantize_info->colorspace == TransparentColorspace)
00703     associate_alpha=MagickFalse;
00704   if ((cube_info->quantize_info->number_colors == 2) &&
00705       (cube_info->quantize_info->colorspace == GRAYColorspace))
00706     associate_alpha=MagickFalse;
00707   cube_info->associate_alpha=associate_alpha;
00708 }
00709 
00710 static MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
00711   const Image *image,ExceptionInfo *exception)
00712 {
00713 #define ClassifyImageTag  "Classify/Image"
00714 
00715   long
00716     y;
00717 
00718   MagickBooleanType
00719     proceed;
00720 
00721   MagickRealType
00722     bisect;
00723 
00724   NodeInfo
00725     *node_info;
00726 
00727   RealPixelPacket
00728     error,
00729     mid,
00730     midpoint,
00731     pixel;
00732 
00733   size_t
00734     count;
00735 
00736   unsigned long
00737     id,
00738     index,
00739     level;
00740 
00741   CacheView
00742     *image_view;
00743 
00744   /*
00745     Classify the first cube_info->maximum_colors colors to a tree depth of 8.
00746   */
00747   SetAssociatedAlpha(image,cube_info);
00748   if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
00749       (cube_info->quantize_info->colorspace != CMYKColorspace))
00750     (void) TransformImageColorspace((Image *) image,
00751       cube_info->quantize_info->colorspace);
00752   else
00753     if ((image->colorspace != GRAYColorspace) &&
00754         (image->colorspace != CMYColorspace) &&
00755         (image->colorspace != RGBColorspace))
00756       (void) TransformImageColorspace((Image *) image,RGBColorspace);
00757   midpoint.red=(MagickRealType) QuantumRange/2.0;
00758   midpoint.green=(MagickRealType) QuantumRange/2.0;
00759   midpoint.blue=(MagickRealType) QuantumRange/2.0;
00760   midpoint.opacity=(MagickRealType) QuantumRange/2.0;
00761   error.opacity=0.0;
00762   image_view=AcquireCacheView(image);
00763   for (y=0; y < (long) image->rows; y++)
00764   {
00765     register const PixelPacket
00766       *__restrict p;
00767 
00768     register long
00769       x;
00770 
00771     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00772     if (p == (const PixelPacket *) NULL)
00773       break;
00774     if (cube_info->nodes > MaxNodes)
00775       {
00776         /*
00777           Prune one level if the color tree is too large.
00778         */
00779         PruneLevel(image,cube_info,cube_info->root);
00780         cube_info->depth--;
00781       }
00782     for (x=0; x < (long) image->columns; x+=(long) count)
00783     {
00784       /*
00785         Start at the root and descend the color cube tree.
00786       */
00787       for (count=1; (x+count) < image->columns; count++)
00788         if (IsSameColor(image,p,p+count) == MagickFalse)
00789           break;
00790       AssociateAlphaPixel(cube_info,p,&pixel);
00791       index=MaxTreeDepth-1;
00792       bisect=((MagickRealType) QuantumRange+1.0)/2.0;
00793       mid=midpoint;
00794       node_info=cube_info->root;
00795       for (level=1; level <= MaxTreeDepth; level++)
00796       {
00797         bisect*=0.5;
00798         id=ColorToNodeId(cube_info,&pixel,index);
00799         mid.red+=(id & 1) != 0 ? bisect : -bisect;
00800         mid.green+=(id & 2) != 0 ? bisect : -bisect;
00801         mid.blue+=(id & 4) != 0 ? bisect : -bisect;
00802         mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
00803         if (node_info->child[id] == (NodeInfo *) NULL)
00804           {
00805             /*
00806               Set colors of new node to contain pixel.
00807             */
00808             node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
00809             if (node_info->child[id] == (NodeInfo *) NULL)
00810               (void) ThrowMagickException(exception,GetMagickModule(),
00811                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
00812                 image->filename);
00813             if (level == MaxTreeDepth)
00814               cube_info->colors++;
00815           }
00816         /*
00817           Approximate the quantization error represented by this node.
00818         */
00819         node_info=node_info->child[id];
00820         error.red=QuantumScale*(pixel.red-mid.red);
00821         error.green=QuantumScale*(pixel.green-mid.green);
00822         error.blue=QuantumScale*(pixel.blue-mid.blue);
00823         if (cube_info->associate_alpha != MagickFalse)
00824           error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
00825         node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
00826           count*error.green*error.green+count*error.blue*error.blue+
00827           count*error.opacity*error.opacity));
00828         cube_info->root->quantize_error+=node_info->quantize_error;
00829         index--;
00830       }
00831       /*
00832         Sum RGB for this leaf for later derivation of the mean cube color.
00833       */
00834       node_info->number_unique+=count;
00835       node_info->total_color.red+=count*QuantumScale*pixel.red;
00836       node_info->total_color.green+=count*QuantumScale*pixel.green;
00837       node_info->total_color.blue+=count*QuantumScale*pixel.blue;
00838       if (cube_info->associate_alpha != MagickFalse)
00839         node_info->total_color.opacity+=count*QuantumScale*pixel.opacity;
00840       p+=count;
00841     }
00842     if (cube_info->colors > cube_info->maximum_colors)
00843       {
00844         PruneToCubeDepth(image,cube_info,cube_info->root);
00845         break;
00846       }
00847     proceed=SetImageProgress(image,ClassifyImageTag,y,image->rows);
00848     if (proceed == MagickFalse)
00849       break;
00850   }
00851   for (y++; y < (long) image->rows; y++)
00852   {
00853     register const PixelPacket
00854       *__restrict p;
00855 
00856     register long
00857       x;
00858 
00859     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00860     if (p == (const PixelPacket *) NULL)
00861       break;
00862     if (cube_info->nodes > MaxNodes)
00863       {
00864         /*
00865           Prune one level if the color tree is too large.
00866         */
00867         PruneLevel(image,cube_info,cube_info->root);
00868         cube_info->depth--;
00869       }
00870     for (x=0; x < (long) image->columns; x+=(long) count)
00871     {
00872       /*
00873         Start at the root and descend the color cube tree.
00874       */
00875       for (count=1; (x+count) < image->columns; count++)
00876         if (IsSameColor(image,p,p+count) == MagickFalse)
00877           break;
00878       AssociateAlphaPixel(cube_info,p,&pixel);
00879       index=MaxTreeDepth-1;
00880       bisect=((MagickRealType) QuantumRange+1.0)/2.0;
00881       mid=midpoint;
00882       node_info=cube_info->root;
00883       for (level=1; level <= cube_info->depth; level++)
00884       {
00885         bisect*=0.5;
00886         id=ColorToNodeId(cube_info,&pixel,index);
00887         mid.red+=(id & 1) != 0 ? bisect : -bisect;
00888         mid.green+=(id & 2) != 0 ? bisect : -bisect;
00889         mid.blue+=(id & 4) != 0 ? bisect : -bisect;
00890         mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
00891         if (node_info->child[id] == (NodeInfo *) NULL)
00892           {
00893             /*
00894               Set colors of new node to contain pixel.
00895             */
00896             node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
00897             if (node_info->child[id] == (NodeInfo *) NULL)
00898               (void) ThrowMagickException(exception,GetMagickModule(),
00899                 ResourceLimitError,"MemoryAllocationFailed","%s",
00900                 image->filename);
00901             if (level == cube_info->depth)
00902               cube_info->colors++;
00903           }
00904         /*
00905           Approximate the quantization error represented by this node.
00906         */
00907         node_info=node_info->child[id];
00908         error.red=QuantumScale*(pixel.red-mid.red);
00909         error.green=QuantumScale*(pixel.green-mid.green);
00910         error.blue=QuantumScale*(pixel.blue-mid.blue);
00911         if (cube_info->associate_alpha != MagickFalse)
00912           error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
00913         node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
00914           count*error.green*error.green+error.blue*error.blue+
00915           count*error.opacity*error.opacity));
00916         cube_info->root->quantize_error+=node_info->quantize_error;
00917         index--;
00918       }
00919       /*
00920         Sum RGB for this leaf for later derivation of the mean cube color.
00921       */
00922       node_info->number_unique+=count;
00923       node_info->total_color.red+=count*QuantumScale*pixel.red;
00924       node_info->total_color.green+=count*QuantumScale*pixel.green;
00925       node_info->total_color.blue+=count*QuantumScale*pixel.blue;
00926       if (cube_info->associate_alpha != MagickFalse)
00927         node_info->total_color.opacity+=count*QuantumScale*pixel.opacity;
00928       p+=count;
00929     }
00930     proceed=SetImageProgress(image,ClassifyImageTag,y,image->rows);
00931     if (proceed == MagickFalse)
00932       break;
00933   }
00934   image_view=DestroyCacheView(image_view);
00935   if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
00936       (cube_info->quantize_info->colorspace != CMYKColorspace))
00937     (void) TransformImageColorspace((Image *) image,RGBColorspace);
00938   return(MagickTrue);
00939 }
00940 
00941 /*
00942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00943 %                                                                             %
00944 %                                                                             %
00945 %                                                                             %
00946 %   C l o n e Q u a n t i z e I n f o                                         %
00947 %                                                                             %
00948 %                                                                             %
00949 %                                                                             %
00950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00951 %
00952 %  CloneQuantizeInfo() makes a duplicate of the given quantize info structure,
00953 %  or if quantize info is NULL, a new one.
00954 %
00955 %  The format of the CloneQuantizeInfo method is:
00956 %
00957 %      QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
00958 %
00959 %  A description of each parameter follows:
00960 %
00961 %    o clone_info: Method CloneQuantizeInfo returns a duplicate of the given
00962 %      quantize info, or if image info is NULL a new one.
00963 %
00964 %    o quantize_info: a structure of type info.
00965 %
00966 */
00967 MagickExport QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
00968 {
00969   QuantizeInfo
00970     *clone_info;
00971 
00972   clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
00973   if (clone_info == (QuantizeInfo *) NULL)
00974     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00975   GetQuantizeInfo(clone_info);
00976   if (quantize_info == (QuantizeInfo *) NULL)
00977     return(clone_info);
00978   clone_info->number_colors=quantize_info->number_colors;
00979   clone_info->tree_depth=quantize_info->tree_depth;
00980   clone_info->dither=quantize_info->dither;
00981   clone_info->dither_method=quantize_info->dither_method;
00982   clone_info->colorspace=quantize_info->colorspace;
00983   clone_info->measure_error=quantize_info->measure_error;
00984   return(clone_info);
00985 }
00986 
00987 /*
00988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00989 %                                                                             %
00990 %                                                                             %
00991 %                                                                             %
00992 +   C l o s e s t C o l o r                                                   %
00993 %                                                                             %
00994 %                                                                             %
00995 %                                                                             %
00996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00997 %
00998 %  ClosestColor() traverses the color cube tree at a particular node and
00999 %  determines which colormap entry best represents the input color.
01000 %
01001 %  The format of the ClosestColor method is:
01002 %
01003 %      void ClosestColor(const Image *image,CubeInfo *cube_info,
01004 %        const NodeInfo *node_info)
01005 %
01006 %  A description of each parameter follows.
01007 %
01008 %    o image: the image.
01009 %
01010 %    o cube_info: A pointer to the Cube structure.
01011 %
01012 %    o node_info: the address of a structure of type NodeInfo which points to a
01013 %      node in the color cube tree that is to be pruned.
01014 %
01015 */
01016 static void ClosestColor(const Image *image,CubeInfo *cube_info,
01017   const NodeInfo *node_info)
01018 {
01019   register long
01020     i;
01021 
01022   unsigned long
01023     number_children;
01024 
01025   /*
01026     Traverse any children.
01027   */
01028   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
01029   for (i=0; i < (long) number_children; i++)
01030     if (node_info->child[i] != (NodeInfo *) NULL)
01031       ClosestColor(image,cube_info,node_info->child[i]);
01032   if (node_info->number_unique != 0)
01033     {
01034       MagickRealType
01035         pixel;
01036 
01037       register MagickRealType
01038         alpha,
01039         beta,
01040         distance;
01041 
01042       register PixelPacket
01043         *__restrict p;
01044 
01045       register RealPixelPacket
01046         *__restrict q;
01047 
01048       /*
01049         Determine if this color is "closest".
01050       */
01051       p=image->colormap+node_info->color_number;
01052       q=(&cube_info->target);
01053       alpha=1.0;
01054       beta=1.0;
01055       if (cube_info->associate_alpha == MagickFalse)
01056         {
01057           alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
01058           beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
01059         }
01060       pixel=alpha*p->red-beta*q->red;
01061       distance=pixel*pixel;
01062       if (distance < cube_info->distance)
01063         {
01064           pixel=alpha*p->green-beta*q->green;
01065           distance+=pixel*pixel;
01066           if (distance < cube_info->distance)
01067             {
01068               pixel=alpha*p->blue-beta*q->blue;
01069               distance+=pixel*pixel;
01070               if (distance < cube_info->distance)
01071                 {
01072                   pixel=alpha-beta;
01073                   distance+=pixel*pixel;
01074                   if (distance < cube_info->distance)
01075                     {
01076                       cube_info->distance=distance;
01077                       cube_info->color_number=node_info->color_number;
01078                     }
01079                 }
01080             }
01081         }
01082     }
01083 }
01084 
01085 /*
01086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01087 %                                                                             %
01088 %                                                                             %
01089 %                                                                             %
01090 %   C o m p r e s s I m a g e C o l o r m a p                                 %
01091 %                                                                             %
01092 %                                                                             %
01093 %                                                                             %
01094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01095 %
01096 %  CompressImageColormap() compresses an image colormap by removing any
01097 %  duplicate or unused color entries.
01098 %
01099 %  The format of the CompressImageColormap method is:
01100 %
01101 %      MagickBooleanType CompressImageColormap(Image *image)
01102 %
01103 %  A description of each parameter follows:
01104 %
01105 %    o image: the image.
01106 %
01107 */
01108 MagickExport MagickBooleanType CompressImageColormap(Image *image)
01109 {
01110   QuantizeInfo
01111     quantize_info;
01112 
01113   assert(image != (Image *) NULL);
01114   assert(image->signature == MagickSignature);
01115   if (image->debug != MagickFalse)
01116     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01117   if (IsPaletteImage(image,&image->exception) == MagickFalse)
01118     return(MagickFalse);
01119   GetQuantizeInfo(&quantize_info);
01120   quantize_info.number_colors=image->colors;
01121   quantize_info.tree_depth=MaxTreeDepth;
01122   return(QuantizeImage(&quantize_info,image));
01123 }
01124 
01125 /*
01126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01127 %                                                                             %
01128 %                                                                             %
01129 %                                                                             %
01130 +   D e f i n e I m a g e C o l o r m a p                                     %
01131 %                                                                             %
01132 %                                                                             %
01133 %                                                                             %
01134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01135 %
01136 %  DefineImageColormap() traverses the color cube tree and notes each colormap
01137 %  entry.  A colormap entry is any node in the color cube tree where the
01138 %  of unique colors is not zero.  DefineImageColormap() returns the number of
01139 %  colors in the image colormap.
01140 %
01141 %  The format of the DefineImageColormap method is:
01142 %
01143 %      unsigned long DefineImageColormap(Image *image,CubeInfo *cube_info,
01144 %        NodeInfo *node_info)
01145 %
01146 %  A description of each parameter follows.
01147 %
01148 %    o image: the image.
01149 %
01150 %    o cube_info: A pointer to the Cube structure.
01151 %
01152 %    o node_info: the address of a structure of type NodeInfo which points to a
01153 %      node in the color cube tree that is to be pruned.
01154 %
01155 */
01156 static unsigned long DefineImageColormap(Image *image,CubeInfo *cube_info,
01157   NodeInfo *node_info)
01158 {
01159   register long
01160     i;
01161 
01162   unsigned long
01163     number_children;
01164 
01165   /*
01166     Traverse any children.
01167   */
01168   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
01169   for (i=0; i < (long) number_children; i++)
01170     if (node_info->child[i] != (NodeInfo *) NULL)
01171       DefineImageColormap(image,cube_info,node_info->child[i]);
01172   if (node_info->number_unique != 0)
01173     {
01174       register MagickRealType
01175         alpha;
01176 
01177       register PixelPacket
01178         *__restrict q;
01179 
01180       /*
01181         Colormap entry is defined by the mean color in this cube.
01182       */
01183       q=image->colormap+image->colors;
01184       alpha=(MagickRealType) ((MagickOffsetType) node_info->number_unique);
01185       alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
01186       if (cube_info->associate_alpha == MagickFalse)
01187         {
01188           q->red=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01189             node_info->total_color.red));
01190           q->green=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01191             node_info->total_color.green));
01192           q->blue=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01193             node_info->total_color.blue));
01194           q->opacity=OpaqueOpacity;
01195         }
01196       else
01197         {
01198           MagickRealType
01199             opacity;
01200 
01201           opacity=(MagickRealType) (alpha*QuantumRange*
01202             node_info->total_color.opacity);
01203           q->opacity=RoundToQuantum(opacity);
01204           if (q->opacity == OpaqueOpacity)
01205             {
01206               q->red=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01207                 node_info->total_color.red));
01208               q->green=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01209                 node_info->total_color.green));
01210               q->blue=RoundToQuantum((MagickRealType) (alpha*QuantumRange*
01211                 node_info->total_color.blue));
01212             }
01213           else
01214             {
01215               MagickRealType
01216                 gamma;
01217 
01218               gamma=(MagickRealType) (QuantumScale*(QuantumRange-
01219                 (MagickRealType) q->opacity));
01220               gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
01221               q->red=RoundToQuantum((MagickRealType) (alpha*gamma*QuantumRange*
01222                 node_info->total_color.red));
01223               q->green=RoundToQuantum((MagickRealType) (alpha*gamma*
01224                 QuantumRange*node_info->total_color.green));
01225               q->blue=RoundToQuantum((MagickRealType) (alpha*gamma*QuantumRange*
01226                 node_info->total_color.blue));
01227               if (node_info->number_unique > cube_info->transparent_pixels)
01228                 {
01229                   cube_info->transparent_pixels=node_info->number_unique;
01230                   cube_info->transparent_index=(long) image->colors;
01231                 }
01232             }
01233         }
01234       node_info->color_number=image->colors++;
01235     }
01236   return(image->colors);
01237 }
01238 
01239 /*
01240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01241 %                                                                             %
01242 %                                                                             %
01243 %                                                                             %
01244 +   D e s t r o y C u b e I n f o                                             %
01245 %                                                                             %
01246 %                                                                             %
01247 %                                                                             %
01248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01249 %
01250 %  DestroyCubeInfo() deallocates memory associated with an image.
01251 %
01252 %  The format of the DestroyCubeInfo method is:
01253 %
01254 %      DestroyCubeInfo(CubeInfo *cube_info)
01255 %
01256 %  A description of each parameter follows:
01257 %
01258 %    o cube_info: the address of a structure of type CubeInfo.
01259 %
01260 */
01261 static void DestroyCubeInfo(CubeInfo *cube_info)
01262 {
01263   register Nodes
01264     *nodes;
01265 
01266   /*
01267     Release color cube tree storage.
01268   */
01269   do
01270   {
01271     nodes=cube_info->node_queue->next;
01272     cube_info->node_queue->nodes=(NodeInfo *) RelinquishMagickMemory(
01273       cube_info->node_queue->nodes);
01274     cube_info->node_queue=(Nodes *) RelinquishMagickMemory(
01275       cube_info->node_queue);
01276     cube_info->node_queue=nodes;
01277   } while (cube_info->node_queue != (Nodes *) NULL);
01278   if (cube_info->cache != (long *) NULL)
01279     cube_info->cache=(long *) RelinquishMagickMemory(cube_info->cache);
01280   cube_info->quantize_info=DestroyQuantizeInfo(cube_info->quantize_info);
01281   cube_info=(CubeInfo *) RelinquishMagickMemory(cube_info);
01282 }
01283 
01284 /*
01285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01286 %                                                                             %
01287 %                                                                             %
01288 %                                                                             %
01289 %   D e s t r o y Q u a n t i z e I n f o                                     %
01290 %                                                                             %
01291 %                                                                             %
01292 %                                                                             %
01293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01294 %
01295 %  DestroyQuantizeInfo() deallocates memory associated with an QuantizeInfo
01296 %  structure.
01297 %
01298 %  The format of the DestroyQuantizeInfo method is:
01299 %
01300 %      QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
01301 %
01302 %  A description of each parameter follows:
01303 %
01304 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
01305 %
01306 */
01307 MagickExport QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
01308 {
01309   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
01310   assert(quantize_info != (QuantizeInfo *) NULL);
01311   assert(quantize_info->signature == MagickSignature);
01312   quantize_info->signature=(~MagickSignature);
01313   quantize_info=(QuantizeInfo *) RelinquishMagickMemory(quantize_info);
01314   return(quantize_info);
01315 }
01316 
01317 /*
01318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01319 %                                                                             %
01320 %                                                                             %
01321 %                                                                             %
01322 +   D i t h e r I m a g e                                                     %
01323 %                                                                             %
01324 %                                                                             %
01325 %                                                                             %
01326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01327 %
01328 %  DitherImage() distributes the difference between an original image and
01329 %  the corresponding color reduced algorithm to neighboring pixels using
01330 %  serpentine-scan Floyd-Steinberg error diffusion. DitherImage returns
01331 %  MagickTrue if the image is dithered otherwise MagickFalse.
01332 %
01333 %  The format of the DitherImage method is:
01334 %
01335 %      MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
01336 %
01337 %  A description of each parameter follows.
01338 %
01339 %    o image: the image.
01340 %
01341 %    o cube_info: A pointer to the Cube structure.
01342 %
01343 */
01344 
01345 static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info)
01346 {
01347 #define DitherImageTag  "Dither/Image"
01348 
01349   ExceptionInfo
01350     *exception;
01351 
01352   long
01353     u,
01354     v,
01355     y;
01356 
01357   MagickBooleanType
01358     proceed;
01359 
01360   RealPixelPacket
01361     color,
01362     *current,
01363     pixel,
01364     *previous,
01365     *scanlines;
01366 
01367   register CubeInfo
01368     *p;
01369 
01370   unsigned long
01371     index;
01372 
01373   CacheView
01374     *image_view;
01375 
01376   /*
01377     Distribute quantization error using Floyd-Steinberg.
01378   */
01379   scanlines=(RealPixelPacket *) AcquireQuantumMemory(image->columns,
01380     2*sizeof(*scanlines));
01381   if (scanlines == (RealPixelPacket *) NULL)
01382     return(MagickFalse);
01383   p=cube_info;
01384   exception=(&image->exception);
01385   image_view=AcquireCacheView(image);
01386   for (y=0; y < (long) image->rows; y++)
01387   {
01388     register IndexPacket
01389       *__restrict indexes;
01390 
01391     register long
01392       i,
01393       x;
01394 
01395     register PixelPacket
01396       *__restrict q;
01397 
01398     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01399     if (q == (PixelPacket *) NULL)
01400       return(MagickFalse);
01401     indexes=GetCacheViewAuthenticIndexQueue(image_view);
01402     current=scanlines+(y & 0x01)*image->columns;
01403     previous=scanlines+((y+1) & 0x01)*image->columns;
01404     v=(y & 0x01) ? -1 : 1;
01405     for (x=0; x < (long) image->columns; x++)
01406     {
01407       u=(y & 0x01) ? (long) image->columns-1-x : x;
01408       AssociateAlphaPixel(cube_info,q+u,&pixel);
01409       if (x > 0)
01410         {
01411           pixel.red+=7*current[u-v].red/16;
01412           pixel.green+=7*current[u-v].green/16;
01413           pixel.blue+=7*current[u-v].blue/16;
01414           if (cube_info->associate_alpha != MagickFalse)
01415             pixel.opacity+=7*current[u-v].opacity/16;
01416         }
01417       if (y > 0)
01418         {
01419           if (x < (long) (image->columns-1))
01420             {
01421               pixel.red+=previous[u+v].red/16;
01422               pixel.green+=previous[u+v].green/16;
01423               pixel.blue+=previous[u+v].blue/16;
01424               if (cube_info->associate_alpha != MagickFalse)
01425                 pixel.opacity+=previous[u+v].opacity/16;
01426             }
01427           pixel.red+=5*previous[u].red/16;
01428           pixel.green+=5*previous[u].green/16;
01429           pixel.blue+=5*previous[u].blue/16;
01430           if (cube_info->associate_alpha != MagickFalse)
01431             pixel.opacity+=5*previous[u].opacity/16;
01432           if (x > 0)
01433             {
01434               pixel.red+=3*previous[u-v].red/16;
01435               pixel.green+=3*previous[u-v].green/16;
01436               pixel.blue+=3*previous[u-v].blue/16;
01437               if (cube_info->associate_alpha != MagickFalse)
01438                 pixel.opacity+=3*previous[u-v].opacity/16;
01439             }
01440         }
01441       pixel.red=(MagickRealType) ClipToQuantum(pixel.red);
01442       pixel.green=(MagickRealType) ClipToQuantum(pixel.green);
01443       pixel.blue=(MagickRealType) ClipToQuantum(pixel.blue);
01444       if (cube_info->associate_alpha != MagickFalse)
01445         pixel.opacity=(MagickRealType) ClipToQuantum(pixel.opacity);
01446       i=(long) ((ScaleQuantumToChar(ClipToQuantum(pixel.red)) >> CacheShift) |
01447         (ScaleQuantumToChar(ClipToQuantum(pixel.green)) >> CacheShift) << 6 |
01448         (ScaleQuantumToChar(ClipToQuantum(pixel.blue)) >> CacheShift) << 12);
01449       if (cube_info->associate_alpha != MagickFalse)
01450         i|=((ScaleQuantumToChar(ClipToQuantum(pixel.opacity)) >> CacheShift)
01451           << 18);
01452       if (p->cache[i] < 0)
01453         {
01454           register NodeInfo
01455             *node_info;
01456 
01457           register unsigned long
01458             id;
01459 
01460           /*
01461             Identify the deepest node containing the pixel's color.
01462           */
01463           node_info=p->root;
01464           for (index=MaxTreeDepth-1; (long) index > 0; index--)
01465           {
01466             id=ColorToNodeId(cube_info,&pixel,index);
01467             if (node_info->child[id] == (NodeInfo *) NULL)
01468               break;
01469             node_info=node_info->child[id];
01470           }
01471           /*
01472             Find closest color among siblings and their children.
01473           */
01474           p->target=pixel;
01475           p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
01476             1.0)+1.0);
01477           ClosestColor(image,p,node_info->parent);
01478           p->cache[i]=(long) p->color_number;
01479         }
01480       /*
01481         Assign pixel to closest colormap entry.
01482       */
01483       index=(unsigned long) p->cache[i];
01484       if (image->storage_class == PseudoClass)
01485         indexes[u]=(IndexPacket) index;
01486       if (cube_info->quantize_info->measure_error == MagickFalse)
01487         {
01488           (q+u)->red=image->colormap[index].red;
01489           (q+u)->green=image->colormap[index].green;
01490           (q+u)->blue=image->colormap[index].blue;
01491           if (cube_info->associate_alpha != MagickFalse)
01492             (q+u)->opacity=image->colormap[index].opacity;
01493         }
01494       if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01495         return(MagickFalse);
01496       /*
01497         Store the error.
01498       */
01499       AssociateAlphaPixel(cube_info,image->colormap+index,&color);
01500       current[u].red=pixel.red-color.red;
01501       current[u].green=pixel.green-color.green;
01502       current[u].blue=pixel.blue-color.blue;
01503       if (cube_info->associate_alpha != MagickFalse)
01504         current[u].opacity=pixel.opacity-color.opacity;
01505       proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
01506       if (proceed == MagickFalse)
01507         return(MagickFalse);
01508       p->offset++;
01509     }
01510   }
01511   scanlines=(RealPixelPacket *) RelinquishMagickMemory(scanlines);
01512   image_view=DestroyCacheView(image_view);
01513   return(MagickTrue);
01514 }
01515 
01516 static MagickBooleanType
01517   RiemersmaDither(Image *,CacheView *,CubeInfo *,const unsigned int);
01518 
01519 static void Riemersma(Image *image,CacheView *image_view,CubeInfo *cube_info,
01520   const unsigned long level,const unsigned int direction)
01521 {
01522   if (level == 1)
01523     switch (direction)
01524     {
01525       case WestGravity:
01526       {
01527         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01528         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01529         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01530         break;
01531       }
01532       case EastGravity:
01533       {
01534         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01535         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01536         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01537         break;
01538       }
01539       case NorthGravity:
01540       {
01541         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01542         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01543         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01544         break;
01545       }
01546       case SouthGravity:
01547       {
01548         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01549         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01550         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01551         break;
01552       }
01553       default:
01554         break;
01555     }
01556   else
01557     switch (direction)
01558     {
01559       case WestGravity:
01560       {
01561         Riemersma(image,image_view,cube_info,level-1,NorthGravity);
01562         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01563         Riemersma(image,image_view,cube_info,level-1,WestGravity);
01564         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01565         Riemersma(image,image_view,cube_info,level-1,WestGravity);
01566         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01567         Riemersma(image,image_view,cube_info,level-1,SouthGravity);
01568         break;
01569       }
01570       case EastGravity:
01571       {
01572         Riemersma(image,image_view,cube_info,level-1,SouthGravity);
01573         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01574         Riemersma(image,image_view,cube_info,level-1,EastGravity);
01575         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01576         Riemersma(image,image_view,cube_info,level-1,EastGravity);
01577         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01578         Riemersma(image,image_view,cube_info,level-1,NorthGravity);
01579         break;
01580       }
01581       case NorthGravity:
01582       {
01583         Riemersma(image,image_view,cube_info,level-1,WestGravity);
01584         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01585         Riemersma(image,image_view,cube_info,level-1,NorthGravity);
01586         (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
01587         Riemersma(image,image_view,cube_info,level-1,NorthGravity);
01588         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01589         Riemersma(image,image_view,cube_info,level-1,EastGravity);
01590         break;
01591       }
01592       case SouthGravity:
01593       {
01594         Riemersma(image,image_view,cube_info,level-1,EastGravity);
01595         (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
01596         Riemersma(image,image_view,cube_info,level-1,SouthGravity);
01597         (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
01598         Riemersma(image,image_view,cube_info,level-1,SouthGravity);
01599         (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
01600         Riemersma(image,image_view,cube_info,level-1,WestGravity);
01601         break;
01602       }
01603       default:
01604         break;
01605     }
01606 }
01607 
01608 static MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
01609   CubeInfo *cube_info,const unsigned int direction)
01610 {
01611 #define DitherImageTag  "Dither/Image"
01612 
01613   MagickBooleanType
01614     proceed;
01615 
01616   RealPixelPacket
01617     color,
01618     pixel;
01619 
01620   register CubeInfo
01621     *p;
01622 
01623   unsigned long
01624     index;
01625 
01626   p=cube_info;
01627   if ((p->x >= 0) && (p->x < (long) image->columns) &&
01628       (p->y >= 0) && (p->y < (long) image->rows))
01629     {
01630       ExceptionInfo
01631         *exception;
01632 
01633       register IndexPacket
01634         *__restrict indexes;
01635 
01636       register long
01637         i;
01638 
01639       register PixelPacket
01640         *__restrict q;
01641 
01642       /*
01643         Distribute error.
01644       */
01645       exception=(&image->exception);
01646       q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
01647       if (q == (PixelPacket *) NULL)
01648         return(MagickFalse);
01649       indexes=GetCacheViewAuthenticIndexQueue(image_view);
01650       AssociateAlphaPixel(cube_info,q,&pixel);
01651       for (i=0; i < ErrorQueueLength; i++)
01652       {
01653         pixel.red+=p->weights[i]*p->error[i].red;
01654         pixel.green+=p->weights[i]*p->error[i].green;
01655         pixel.blue+=p->weights[i]*p->error[i].blue;
01656         if (cube_info->associate_alpha != MagickFalse)
01657           pixel.opacity+=p->weights[i]*p->error[i].opacity;
01658       }
01659       pixel.red=(MagickRealType) ClipToQuantum(pixel.red);
01660       pixel.green=(MagickRealType) ClipToQuantum(pixel.green);
01661       pixel.blue=(MagickRealType) ClipToQuantum(pixel.blue);
01662       if (cube_info->associate_alpha != MagickFalse)
01663         pixel.opacity=(MagickRealType) ClipToQuantum(pixel.opacity);
01664       i=(long) ((ScaleQuantumToChar(ClipToQuantum(pixel.red)) >> CacheShift) |
01665         (ScaleQuantumToChar(ClipToQuantum(pixel.green)) >> CacheShift) << 6 |
01666         (ScaleQuantumToChar(ClipToQuantum(pixel.blue)) >> CacheShift) << 12);
01667       if (cube_info->associate_alpha != MagickFalse)
01668         i|=((ScaleQuantumToChar(ClipToQuantum(pixel.opacity)) >> CacheShift)
01669           << 18);
01670       if (p->cache[i] < 0)
01671         {
01672           register NodeInfo
01673             *node_info;
01674 
01675           register unsigned long
01676             id;
01677 
01678           /*
01679             Identify the deepest node containing the pixel's color.
01680           */
01681           node_info=p->root;
01682           for (index=MaxTreeDepth-1; (long) index > 0; index--)
01683           {
01684             id=ColorToNodeId(cube_info,&pixel,index);
01685             if (node_info->child[id] == (NodeInfo *) NULL)
01686               break;
01687             node_info=node_info->child[id];
01688           }
01689           /*
01690             Find closest color among siblings and their children.
01691           */
01692           p->target=pixel;
01693           p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*((MagickRealType)
01694             QuantumRange+1.0)+1.0);
01695           ClosestColor(image,p,node_info->parent);
01696           p->cache[i]=(long) p->color_number;
01697         }
01698       /*
01699         Assign pixel to closest colormap entry.
01700       */
01701       index=(unsigned long) (1*p->cache[i]);
01702       if (image->storage_class == PseudoClass)
01703         *indexes=(IndexPacket) index;
01704       if (cube_info->quantize_info->measure_error == MagickFalse)
01705         {
01706           q->red=image->colormap[index].red;
01707           q->green=image->colormap[index].green;
01708           q->blue=image->colormap[index].blue;
01709           if (cube_info->associate_alpha != MagickFalse)
01710             q->opacity=image->colormap[index].opacity;
01711         }
01712       if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01713         return(MagickFalse);
01714       /*
01715         Propagate the error as the last entry of the error queue.
01716       */
01717       (void) CopyMagickMemory(p->error,p->error+1,(ErrorQueueLength-1)*
01718         sizeof(p->error[0]));
01719       AssociateAlphaPixel(cube_info,image->colormap+index,&color);
01720       p->error[ErrorQueueLength-1].red=pixel.red-color.red;
01721       p->error[ErrorQueueLength-1].green=pixel.green-color.green;
01722       p->error[ErrorQueueLength-1].blue=pixel.blue-color.blue;
01723       if (cube_info->associate_alpha != MagickFalse)
01724         p->error[ErrorQueueLength-1].opacity=pixel.opacity-color.opacity;
01725       proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
01726       if (proceed == MagickFalse)
01727         return(MagickFalse);
01728       p->offset++;
01729     }
01730   switch (direction)
01731   {
01732     case WestGravity: p->x--; break;
01733     case EastGravity: p->x++; break;
01734     case NorthGravity: p->y--; break;
01735     case SouthGravity: p->y++; break;
01736   }
01737   return(MagickTrue);
01738 }
01739 
01740 static inline long MagickMax(const long x,const long y)
01741 {
01742   if (x > y)
01743     return(x);
01744   return(y);
01745 }
01746 
01747 static inline long MagickMin(const long x,const long y)
01748 {
01749   if (x < y)
01750     return(x);
01751   return(y);
01752 }
01753 
01754 static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
01755 {
01756   MagickBooleanType
01757     status;
01758 
01759   register long
01760     i;
01761 
01762   unsigned long
01763     depth;
01764 
01765   CacheView
01766     *image_view;
01767 
01768   if (cube_info->quantize_info->dither_method == FloydSteinbergDitherMethod)
01769     return(FloydSteinbergDither(image,cube_info));
01770   /*
01771     Distribute quantization error along a Hilbert curve.
01772   */
01773   (void) ResetMagickMemory(cube_info->error,0,ErrorQueueLength*
01774     sizeof(*cube_info->error));
01775   cube_info->x=0;
01776   cube_info->y=0;
01777   i=MagickMax((long) image->columns,(long) image->rows);
01778   for (depth=1; i != 0; depth++)
01779     i>>=1;
01780   if ((long) (1L << depth) < MagickMax((long) image->columns,(long) image->rows))
01781     depth++;
01782   cube_info->offset=0;
01783   cube_info->span=(MagickSizeType) image->columns*image->rows;
01784   image_view=AcquireCacheView(image);
01785   if (depth > 1)
01786     Riemersma(image,image_view,cube_info,depth-1,NorthGravity);
01787   status=RiemersmaDither(image,image_view,cube_info,ForgetGravity);
01788   image_view=DestroyCacheView(image_view);
01789   return(status);
01790 }
01791 
01792 /*
01793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01794 %                                                                             %
01795 %                                                                             %
01796 %                                                                             %
01797 +   G e t C u b e I n f o                                                     %
01798 %                                                                             %
01799 %                                                                             %
01800 %                                                                             %
01801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01802 %
01803 %  GetCubeInfo() initialize the Cube data structure.
01804 %
01805 %  The format of the GetCubeInfo method is:
01806 %
01807 %      CubeInfo GetCubeInfo(const QuantizeInfo *quantize_info,
01808 %        const unsigned long depth,const unsigned long maximum_colors)
01809 %
01810 %  A description of each parameter follows.
01811 %
01812 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
01813 %
01814 %    o depth: Normally, this integer value is zero or one.  A zero or
01815 %      one tells Quantize to choose a optimal tree depth of Log4(number_colors).
01816 %      A tree of this depth generally allows the best representation of the
01817 %      reference image with the least amount of memory and the fastest
01818 %      computational speed.  In some cases, such as an image with low color
01819 %      dispersion (a few number of colors), a value other than
01820 %      Log4(number_colors) is required.  To expand the color tree completely,
01821 %      use a value of 8.
01822 %
01823 %    o maximum_colors: maximum colors.
01824 %
01825 */
01826 static CubeInfo *GetCubeInfo(const QuantizeInfo *quantize_info,
01827   const unsigned long depth,const unsigned long maximum_colors)
01828 {
01829   CubeInfo
01830     *cube_info;
01831 
01832   MagickRealType
01833     sum,
01834     weight;
01835 
01836   size_t
01837     length;
01838 
01839   register long
01840     i;
01841 
01842   /*
01843     Initialize tree to describe color cube_info.
01844   */
01845   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
01846   if (cube_info == (CubeInfo *) NULL)
01847     return((CubeInfo *) NULL);
01848   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
01849   cube_info->depth=depth;
01850   if (cube_info->depth > MaxTreeDepth)
01851     cube_info->depth=MaxTreeDepth;
01852   if (cube_info->depth < 2)
01853     cube_info->depth=2;
01854   cube_info->maximum_colors=maximum_colors;
01855   /*
01856     Initialize root node.
01857   */
01858   cube_info->root=GetNodeInfo(cube_info,0,0,(NodeInfo *) NULL);
01859   if (cube_info->root == (NodeInfo *) NULL)
01860     return((CubeInfo *) NULL);
01861   cube_info->root->parent=cube_info->root;
01862   cube_info->quantize_info=CloneQuantizeInfo(quantize_info);
01863   if (cube_info->quantize_info->dither == MagickFalse)
01864     return(cube_info);
01865   /*
01866     Initialize dither resources.
01867   */
01868   length=(size_t) (1UL << (4*(8-CacheShift)));
01869   cube_info->cache=(long *) AcquireQuantumMemory(length,
01870     sizeof(*cube_info->cache));
01871   if (cube_info->cache == (long *) NULL)
01872     return((CubeInfo *) NULL);
01873   /*
01874     Initialize color cache.
01875   */
01876   for (i=0; i < (long) length; i++)
01877     cube_info->cache[i]=(-1);
01878   /*
01879     Distribute weights along a curve of exponential decay.
01880   */
01881   weight=1.0;
01882   for (i=0; i < ErrorQueueLength; i++)
01883   {
01884     cube_info->weights[ErrorQueueLength-i-1]=1.0/weight;
01885     weight*=exp(log(((double) QuantumRange+1.0))/(ErrorQueueLength-1.0));
01886   }
01887   /*
01888     Normalize the weighting factors.
01889   */
01890   weight=0.0;
01891   for (i=0; i < ErrorQueueLength; i++)
01892     weight+=cube_info->weights[i];
01893   sum=0.0;
01894   for (i=0; i < ErrorQueueLength; i++)
01895   {
01896     cube_info->weights[i]/=weight;
01897     sum+=cube_info->weights[i];
01898   }
01899   cube_info->weights[0]+=1.0-sum;
01900   return(cube_info);
01901 }
01902 
01903 /*
01904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01905 %                                                                             %
01906 %                                                                             %
01907 %                                                                             %
01908 +   G e t N o d e I n f o                                                     %
01909 %                                                                             %
01910 %                                                                             %
01911 %                                                                             %
01912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01913 %
01914 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
01915 %  presets all fields to zero.
01916 %
01917 %  The format of the GetNodeInfo method is:
01918 %
01919 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long id,
01920 %        const unsigned long level,NodeInfo *parent)
01921 %
01922 %  A description of each parameter follows.
01923 %
01924 %    o node: The GetNodeInfo method returns a pointer to a queue of nodes.
01925 %
01926 %    o id: Specifies the child number of the node.
01927 %
01928 %    o level: Specifies the level in the storage_class the node resides.
01929 %
01930 */
01931 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long id,
01932   const unsigned long level,NodeInfo *parent)
01933 {
01934   NodeInfo
01935     *node_info;
01936 
01937   if (cube_info->free_nodes == 0)
01938     {
01939       Nodes
01940         *nodes;
01941 
01942       /*
01943         Allocate a new queue of nodes.
01944       */
01945       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
01946       if (nodes == (Nodes *) NULL)
01947         return((NodeInfo *) NULL);
01948       nodes->nodes=(NodeInfo *) AcquireQuantumMemory(NodesInAList,
01949         sizeof(*nodes->nodes));
01950       if (nodes->nodes == (NodeInfo *) NULL)
01951         return((NodeInfo *) NULL);
01952       nodes->next=cube_info->node_queue;
01953       cube_info->node_queue=nodes;
01954       cube_info->next_node=nodes->nodes;
01955       cube_info->free_nodes=NodesInAList;
01956     }
01957   cube_info->nodes++;
01958   cube_info->free_nodes--;
01959   node_info=cube_info->next_node++;
01960   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
01961   node_info->parent=parent;
01962   node_info->id=id;
01963   node_info->level=level;
01964   return(node_info);
01965 }
01966 
01967 /*
01968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01969 %                                                                             %
01970 %                                                                             %
01971 %                                                                             %
01972 %  G e t I m a g e Q u a n t i z e E r r o r                                  %
01973 %                                                                             %
01974 %                                                                             %
01975 %                                                                             %
01976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01977 %
01978 %  GetImageQuantizeError() measures the difference between the original
01979 %  and quantized images.  This difference is the total quantization error.
01980 %  The error is computed by summing over all pixels in an image the distance
01981 %  squared in RGB space between each reference pixel value and its quantized
01982 %  value.  These values are computed:
01983 %
01984 %    o mean_error_per_pixel:  This value is the mean error for any single
01985 %      pixel in the image.
01986 %
01987 %    o normalized_mean_square_error:  This value is the normalized mean
01988 %      quantization error for any single pixel in the image.  This distance
01989 %      measure is normalized to a range between 0 and 1.  It is independent
01990 %      of the range of red, green, and blue values in the image.
01991 %
01992 %    o normalized_maximum_square_error:  Thsi value is the normalized
01993 %      maximum quantization error for any single pixel in the image.  This
01994 %      distance measure is normalized to a range between 0 and 1.  It is
01995 %      independent of the range of red, green, and blue values in your image.
01996 %
01997 %  The format of the GetImageQuantizeError method is:
01998 %
01999 %      MagickBooleanType GetImageQuantizeError(Image *image)
02000 %
02001 %  A description of each parameter follows.
02002 %
02003 %    o image: the image.
02004 %
02005 */
02006 MagickExport MagickBooleanType GetImageQuantizeError(Image *image)
02007 {
02008   ExceptionInfo
02009     *exception;
02010 
02011   IndexPacket
02012     *indexes;
02013 
02014   long
02015     y;
02016 
02017   MagickRealType
02018     alpha,
02019     area,
02020     beta,
02021     distance,
02022     maximum_error,
02023     mean_error,
02024     mean_error_per_pixel;
02025 
02026   unsigned long
02027     index;
02028 
02029   CacheView
02030     *image_view;
02031 
02032   assert(image != (Image *) NULL);
02033   assert(image->signature == MagickSignature);
02034   if (image->debug != MagickFalse)
02035     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02036   image->total_colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
02037   (void) ResetMagickMemory(&image->error,0,sizeof(image->error));
02038   if (image->storage_class == DirectClass)
02039     return(MagickTrue);
02040   alpha=1.0;
02041   beta=1.0;
02042   area=3.0*image->columns*image->rows;
02043   maximum_error=0.0;
02044   mean_error_per_pixel=0.0;
02045   mean_error=0.0;
02046   exception=(&image->exception);
02047   image_view=AcquireCacheView(image);
02048   for (y=0; y < (long) image->rows; y++)
02049   {
02050     register const PixelPacket
02051       *__restrict p;
02052 
02053     register long
02054       x;
02055 
02056     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
02057     if (p == (const PixelPacket *) NULL)
02058       break;
02059     indexes=GetCacheViewAuthenticIndexQueue(image_view);
02060     for (x=0; x < (long) image->columns; x++)
02061     {
02062       index=1UL*indexes[x];
02063       if (image->matte != MagickFalse)
02064         {
02065           alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
02066           beta=(MagickRealType) (QuantumScale*(QuantumRange-
02067             image->colormap[index].opacity));
02068         }
02069       distance=fabs(alpha*p->red-beta*image->colormap[index].red);
02070       mean_error_per_pixel+=distance;
02071       mean_error+=distance*distance;
02072       if (distance > maximum_error)
02073         maximum_error=distance;
02074       distance=fabs(alpha*p->green-beta*image->colormap[index].green);
02075       mean_error_per_pixel+=distance;
02076       mean_error+=distance*distance;
02077       if (distance > maximum_error)
02078         maximum_error=distance;
02079       distance=fabs(alpha*p->blue-beta*image->colormap[index].blue);
02080       mean_error_per_pixel+=distance;
02081       mean_error+=distance*distance;
02082       if (distance > maximum_error)
02083         maximum_error=distance;
02084       p++;
02085     }
02086   }
02087   image_view=DestroyCacheView(image_view);
02088   image->error.mean_error_per_pixel=(double) mean_error_per_pixel/area;
02089   image->error.normalized_mean_error=(double) QuantumScale*QuantumScale*
02090     mean_error/area;
02091   image->error.normalized_maximum_error=(double) QuantumScale*maximum_error;
02092   return(MagickTrue);
02093 }
02094 
02095 /*
02096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02097 %                                                                             %
02098 %                                                                             %
02099 %                                                                             %
02100 %   G e t Q u a n t i z e I n f o                                             %
02101 %                                                                             %
02102 %                                                                             %
02103 %                                                                             %
02104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02105 %
02106 %  GetQuantizeInfo() initializes the QuantizeInfo structure.
02107 %
02108 %  The format of the GetQuantizeInfo method is:
02109 %
02110 %      GetQuantizeInfo(QuantizeInfo *quantize_info)
02111 %
02112 %  A description of each parameter follows:
02113 %
02114 %    o quantize_info: Specifies a pointer to a QuantizeInfo structure.
02115 %
02116 */
02117 MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
02118 {
02119   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
02120   assert(quantize_info != (QuantizeInfo *) NULL);
02121   (void) ResetMagickMemory(quantize_info,0,sizeof(*quantize_info));
02122   quantize_info->number_colors=256;
02123   quantize_info->dither=MagickTrue;
02124   quantize_info->dither_method=RiemersmaDitherMethod;
02125   quantize_info->colorspace=UndefinedColorspace;
02126   quantize_info->measure_error=MagickFalse;
02127   quantize_info->signature=MagickSignature;
02128 }
02129 
02130 /*
02131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02132 %                                                                             %
02133 %                                                                             %
02134 %                                                                             %
02135 %   P o s t e r i z e I m a g e                                               %
02136 %                                                                             %
02137 %                                                                             %
02138 %                                                                             %
02139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02140 %
02141 %  PosterizeImage() reduces the image to a limited number of colors for a
02142 %  "poster" effect.
02143 %
02144 %  The format of the PosterizeImage method is:
02145 %
02146 %      MagickBooleanType PosterizeImage(Image *image,const unsigned long levels,
02147 %        const MagickBooleanType dither)
02148 %
02149 %  A description of each parameter follows:
02150 %
02151 %    o image: Specifies a pointer to an Image structure.
02152 %
02153 %    o levels: Number of color levels allowed in each channel.  Very low values
02154 %      (2, 3, or 4) have the most visible effect.
02155 %
02156 %    o dither: Set this integer value to something other than zero to
02157 %      dither the mapped image.
02158 %
02159 */
02160 MagickExport MagickBooleanType PosterizeImage(Image *image,
02161   const unsigned long levels,const MagickBooleanType dither)
02162 {
02163   ExceptionInfo
02164     *exception;
02165 
02166   Image
02167     *posterize_image;
02168 
02169   IndexPacket
02170     *indexes;
02171 
02172   long
02173     j,
02174     k,
02175     l,
02176     n;
02177 
02178   MagickBooleanType
02179     status;
02180 
02181   QuantizeInfo
02182     *quantize_info;
02183 
02184   register long
02185     i;
02186 
02187   register PixelPacket
02188     *__restrict q;
02189 
02190   CacheView
02191     *posterize_view;
02192 
02193   /*
02194     Posterize image.
02195   */
02196   assert(image != (Image *) NULL);
02197   assert(image->signature == MagickSignature);
02198   if (image->debug != MagickFalse)
02199     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02200   posterize_image=AcquireImage((ImageInfo *) NULL);
02201   if (posterize_image == (Image *) NULL)
02202     return(MagickFalse);
02203   l=1;
02204   while ((l*l*l) < (long) MagickMin((long) levels*levels*levels,MaxColormapSize+1))
02205     l++;
02206   status=SetImageExtent(posterize_image,(unsigned long) (l*l*l),1);
02207   if (status == MagickFalse)
02208     {
02209       posterize_image=DestroyImage(posterize_image);
02210       return(MagickFalse);
02211     }
02212   status=AcquireImageColormap(posterize_image,levels*levels*levels);
02213   if (status == MagickFalse)
02214     {
02215       posterize_image=DestroyImage(posterize_image);
02216       return(MagickFalse);
02217     }
02218   posterize_view=AcquireCacheView(posterize_image);
02219   exception=(&image->exception);
02220   q=QueueCacheViewAuthenticPixels(posterize_view,0,0,posterize_image->columns,1,
02221     exception);
02222   if (q == (PixelPacket *) NULL)
02223     {
02224       posterize_view=DestroyCacheView(posterize_view);
02225       posterize_image=DestroyImage(posterize_image);
02226       return(MagickFalse);
02227     }
02228   indexes=GetCacheViewAuthenticIndexQueue(posterize_view);
02229   n=0;
02230   for (i=0; i < l; i++)
02231     for (j=0; j < l; j++)
02232       for (k=0; k < l; k++)
02233       {
02234         posterize_image->colormap[n].red=(Quantum) (QuantumRange*i/
02235           MagickMax(l-1L,1L));
02236         posterize_image->colormap[n].green=(Quantum)
02237           (QuantumRange*j/MagickMax(l-1L,1L));
02238         posterize_image->colormap[n].blue=(Quantum) (QuantumRange*k/
02239           MagickMax(l-1L,1L));
02240         posterize_image->colormap[n].opacity=OpaqueOpacity;
02241         *q++=posterize_image->colormap[n];
02242         indexes[n]=(IndexPacket) n;
02243         n++;
02244       }
02245   if (SyncCacheViewAuthenticPixels(posterize_view,exception) == MagickFalse)
02246     {
02247       posterize_view=DestroyCacheView(posterize_view);
02248       posterize_image=DestroyImage(posterize_image);
02249       return(MagickFalse);
02250     }
02251   posterize_view=DestroyCacheView(posterize_view);
02252   quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
02253   quantize_info->dither=dither;
02254   status=RemapImage(quantize_info,image,posterize_image);
02255   quantize_info=DestroyQuantizeInfo(quantize_info);
02256   posterize_image=DestroyImage(posterize_image);
02257   return(status);
02258 }
02259 
02260 /*
02261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02262 %                                                                             %
02263 %                                                                             %
02264 %                                                                             %
02265 +   P r u n e C h i l d                                                       %
02266 %                                                                             %
02267 %                                                                             %
02268 %                                                                             %
02269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02270 %
02271 %  PruneChild() deletes the given node and merges its statistics into its
02272 %  parent.
02273 %
02274 %  The format of the PruneSubtree method is:
02275 %
02276 %      PruneChild(const Image *image,CubeInfo *cube_info,
02277 %        const NodeInfo *node_info)
02278 %
02279 %  A description of each parameter follows.
02280 %
02281 %    o image: the image.
02282 %
02283 %    o cube_info: A pointer to the Cube structure.
02284 %
02285 %    o node_info: pointer to node in color cube tree that is to be pruned.
02286 %
02287 */
02288 static void PruneChild(const Image *image,CubeInfo *cube_info,
02289   const NodeInfo *node_info)
02290 {
02291   NodeInfo
02292     *parent;
02293 
02294   register long
02295     i;
02296 
02297   unsigned long
02298     number_children;
02299 
02300   /*
02301     Traverse any children.
02302   */
02303   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
02304   for (i=0; i < (long) number_children; i++)
02305     if (node_info->child[i] != (NodeInfo *) NULL)
02306       PruneChild(image,cube_info,node_info->child[i]);
02307   /*
02308     Merge color statistics into parent.
02309   */
02310   parent=node_info->parent;
02311   parent->number_unique+=node_info->number_unique;
02312   parent->total_color.red+=node_info->total_color.red;
02313   parent->total_color.green+=node_info->total_color.green;
02314   parent->total_color.blue+=node_info->total_color.blue;
02315   parent->total_color.opacity+=node_info->total_color.opacity;
02316   parent->child[node_info->id]=(NodeInfo *) NULL;
02317   cube_info->nodes--;
02318 }
02319 
02320 /*
02321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02322 %                                                                             %
02323 %                                                                             %
02324 %                                                                             %
02325 +  P r u n e L e v e l                                                        %
02326 %                                                                             %
02327 %                                                                             %
02328 %                                                                             %
02329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02330 %
02331 %  PruneLevel() deletes all nodes at the bottom level of the color tree merging
02332 %  their color statistics into their parent node.
02333 %
02334 %  The format of the PruneLevel method is:
02335 %
02336 %      PruneLevel(const Image *image,CubeInfo *cube_info,
02337 %        const NodeInfo *node_info)
02338 %
02339 %  A description of each parameter follows.
02340 %
02341 %    o image: the image.
02342 %
02343 %    o cube_info: A pointer to the Cube structure.
02344 %
02345 %    o node_info: pointer to node in color cube tree that is to be pruned.
02346 %
02347 */
02348 static void PruneLevel(const Image *image,CubeInfo *cube_info,
02349   const NodeInfo *node_info)
02350 {
02351   register long
02352     i;
02353 
02354   unsigned long
02355     number_children;
02356 
02357   /*
02358     Traverse any children.
02359   */
02360   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
02361   for (i=0; i < (long) number_children; i++)
02362     if (node_info->child[i] != (NodeInfo *) NULL)
02363       PruneLevel(image,cube_info,node_info->child[i]);
02364   if (node_info->level == cube_info->depth)
02365     PruneChild(image,cube_info,node_info);
02366 }
02367 
02368 /*
02369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02370 %                                                                             %
02371 %                                                                             %
02372 %                                                                             %
02373 +  P r u n e T o C u b e D e p t h                                            %
02374 %                                                                             %
02375 %                                                                             %
02376 %                                                                             %
02377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02378 %
02379 %  PruneToCubeDepth() deletes any nodes at a depth greater than
02380 %  cube_info->depth while merging their color statistics into their parent
02381 %  node.
02382 %
02383 %  The format of the PruneToCubeDepth method is:
02384 %
02385 %      PruneToCubeDepth(const Image *image,CubeInfo *cube_info,
02386 %        const NodeInfo *node_info)
02387 %
02388 %  A description of each parameter follows.
02389 %
02390 %    o cube_info: A pointer to the Cube structure.
02391 %
02392 %    o node_info: pointer to node in color cube tree that is to be pruned.
02393 %
02394 */
02395 static void PruneToCubeDepth(const Image *image,CubeInfo *cube_info,
02396   const NodeInfo *node_info)
02397 {
02398   register long
02399     i;
02400 
02401   unsigned long
02402     number_children;
02403 
02404   /*
02405     Traverse any children.
02406   */
02407   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
02408   for (i=0; i < (long) number_children; i++)
02409     if (node_info->child[i] != (NodeInfo *) NULL)
02410       PruneToCubeDepth(image,cube_info,node_info->child[i]);
02411   if (node_info->level > cube_info->depth)
02412     PruneChild(image,cube_info,node_info);
02413 }
02414 
02415 /*
02416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02417 %                                                                             %
02418 %                                                                             %
02419 %                                                                             %
02420 %  Q u a n t i z e I m a g e                                                  %
02421 %                                                                             %
02422 %                                                                             %
02423 %                                                                             %
02424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02425 %
02426 %  QuantizeImage() analyzes the colors within a reference image and chooses a
02427 %  fixed number of colors to represent the image.  The goal of the algorithm
02428 %  is to minimize the color difference between the input and output image while
02429 %  minimizing the processing time.
02430 %
02431 %  The format of the QuantizeImage method is:
02432 %
02433 %      MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
02434 %        Image *image)
02435 %
02436 %  A description of each parameter follows:
02437 %
02438 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
02439 %
02440 %    o image: the image.
02441 %
02442 */
02443 MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
02444   Image *image)
02445 {
02446   CubeInfo
02447     *cube_info;
02448 
02449   MagickBooleanType
02450     status;
02451 
02452   unsigned long
02453     depth,
02454     maximum_colors;
02455 
02456   assert(quantize_info != (const QuantizeInfo *) NULL);
02457   assert(quantize_info->signature == MagickSignature);
02458   assert(image != (Image *) NULL);
02459   assert(image->signature == MagickSignature);
02460   if (image->debug != MagickFalse)
02461     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02462   maximum_colors=quantize_info->number_colors;
02463   if (maximum_colors == 0)
02464     maximum_colors=MaxColormapSize;
02465   if (maximum_colors > MaxColormapSize)
02466     maximum_colors=MaxColormapSize;
02467   if ((IsGrayImage(image,&image->exception) != MagickFalse) &&
02468       (image->matte == MagickFalse))
02469     (void) SetGrayscaleImage(image);
02470   if ((image->storage_class == PseudoClass) &&
02471       (image->colors <= maximum_colors))
02472     return(MagickTrue);
02473   depth=quantize_info->tree_depth;
02474   if (depth == 0)
02475     {
02476       unsigned long
02477         colors;
02478 
02479       /*
02480         Depth of color tree is: Log4(colormap size)+2.
02481       */
02482       colors=maximum_colors;
02483       for (depth=1; colors != 0; depth++)
02484         colors>>=2;
02485       if ((quantize_info->dither != MagickFalse) && (depth > 2))
02486         depth--;
02487       if ((image->matte != MagickFalse) && (depth > 5))
02488         depth--;
02489     }
02490   /*
02491     Initialize color cube.
02492   */
02493   cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
02494   if (cube_info == (CubeInfo *) NULL)
02495     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
02496       image->filename);
02497   status=ClassifyImageColors(cube_info,image,&image->exception);
02498   if (status != MagickFalse)
02499     {
02500       /*
02501         Reduce the number of colors in the image.
02502       */
02503       ReduceImageColors(image,cube_info);
02504       status=AssignImageColors(image,cube_info);
02505     }
02506   DestroyCubeInfo(cube_info);
02507   return(status);
02508 }
02509 
02510 /*
02511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02512 %                                                                             %
02513 %                                                                             %
02514 %                                                                             %
02515 %   Q u a n t i z e I m a g e s                                               %
02516 %                                                                             %
02517 %                                                                             %
02518 %                                                                             %
02519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02520 %
02521 %  QuantizeImages() analyzes the colors within a set of reference images and
02522 %  chooses a fixed number of colors to represent the set.  The goal of the
02523 %  algorithm is to minimize the color difference between the input and output
02524 %  images while minimizing the processing time.
02525 %
02526 %  The format of the QuantizeImages method is:
02527 %
02528 %      MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
02529 %        Image *images)
02530 %
02531 %  A description of each parameter follows:
02532 %
02533 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
02534 %
02535 %    o images: Specifies a pointer to a list of Image structures.
02536 %
02537 */
02538 MagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
02539   Image *images)
02540 {
02541   CubeInfo
02542     *cube_info;
02543 
02544   Image
02545     *image;
02546 
02547   MagickBooleanType
02548     proceed,
02549     status;
02550 
02551   MagickProgressMonitor
02552     progress_monitor;
02553 
02554   register long
02555     i;
02556 
02557   unsigned long
02558     depth,
02559     maximum_colors,
02560     number_images;
02561 
02562   assert(quantize_info != (const QuantizeInfo *) NULL);
02563   assert(quantize_info->signature == MagickSignature);
02564   assert(images != (Image *) NULL);
02565   assert(images->signature == MagickSignature);
02566   if (images->debug != MagickFalse)
02567     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
02568   if (GetNextImageInList(images) == (Image *) NULL)
02569     {
02570       /*
02571         Handle a single image with QuantizeImage.
02572       */
02573       status=QuantizeImage(quantize_info,images);
02574       return(status);
02575     }
02576   status=MagickFalse;
02577   maximum_colors=quantize_info->number_colors;
02578   if (maximum_colors == 0)
02579     maximum_colors=MaxColormapSize;
02580   if (maximum_colors > MaxColormapSize)
02581     maximum_colors=MaxColormapSize;
02582   depth=quantize_info->tree_depth;
02583   if (depth == 0)
02584     {
02585       unsigned long
02586         colors;
02587 
02588       /*
02589         Depth of color tree is: Log4(colormap size)+2.
02590       */
02591       colors=maximum_colors;
02592       for (depth=1; colors != 0; depth++)
02593         colors>>=2;
02594       if (quantize_info->dither != MagickFalse)
02595         depth--;
02596     }
02597   /*
02598     Initialize color cube.
02599   */
02600   cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
02601   if (cube_info == (CubeInfo *) NULL)
02602     {
02603       (void) ThrowMagickException(&images->exception,GetMagickModule(),
02604         ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
02605       return(MagickFalse);
02606     }
02607   number_images=GetImageListLength(images);
02608   image=images;
02609   for (i=0; image != (Image *) NULL; i++)
02610   {
02611     progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
02612       image->client_data);
02613     status=ClassifyImageColors(cube_info,image,&image->exception);
02614     if (status == MagickFalse)
02615       break;
02616     (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
02617     proceed=SetImageProgress(image,AssignImageTag,i,number_images);
02618     if (proceed == MagickFalse)
02619       break;
02620     image=GetNextImageInList(image);
02621   }
02622   if (status != MagickFalse)
02623     {
02624       /*
02625         Reduce the number of colors in an image sequence.
02626       */
02627       ReduceImageColors(images,cube_info);
02628       image=images;
02629       for (i=0; image != (Image *) NULL; i++)
02630       {
02631         progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor)
02632           NULL,image->client_data);
02633         status=AssignImageColors(image,cube_info);
02634         if (status == MagickFalse)
02635           break;
02636         (void) SetImageProgressMonitor(image,progress_monitor,
02637           image->client_data);
02638         proceed=SetImageProgress(image,AssignImageTag,i,number_images);
02639         if (proceed == MagickFalse)
02640           break;
02641         image=GetNextImageInList(image);
02642       }
02643     }
02644   DestroyCubeInfo(cube_info);
02645   return(status);
02646 }
02647 
02648 /*
02649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02650 %                                                                             %
02651 %                                                                             %
02652 %                                                                             %
02653 +   R e d u c e                                                               %
02654 %                                                                             %
02655 %                                                                             %
02656 %                                                                             %
02657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02658 %
02659 %  Reduce() traverses the color cube tree and prunes any node whose
02660 %  quantization error falls below a particular threshold.
02661 %
02662 %  The format of the Reduce method is:
02663 %
02664 %      Reduce(const Image *image,CubeInfo *cube_info,const NodeInfo *node_info)
02665 %
02666 %  A description of each parameter follows.
02667 %
02668 %    o image: the image.
02669 %
02670 %    o cube_info: A pointer to the Cube structure.
02671 %
02672 %    o node_info: pointer to node in color cube tree that is to be pruned.
02673 %
02674 */
02675 static void Reduce(const Image *image,CubeInfo *cube_info,
02676   const NodeInfo *node_info)
02677 {
02678   register long
02679     i;
02680 
02681   unsigned long
02682     number_children;
02683 
02684   /*
02685     Traverse any children.
02686   */
02687   number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
02688   for (i=0; i < (long) number_children; i++)
02689     if (node_info->child[i] != (NodeInfo *) NULL)
02690       Reduce(image,cube_info,node_info->child[i]);
02691   if (node_info->quantize_error <= cube_info->pruning_threshold)
02692     PruneChild(image,cube_info,node_info);
02693   else
02694     {
02695       /*
02696         Find minimum pruning threshold.
02697       */
02698       if (node_info->number_unique > 0)
02699         cube_info->colors++;
02700       if (node_info->quantize_error < cube_info->next_threshold)
02701         cube_info->next_threshold=node_info->quantize_error;
02702     }
02703 }
02704 
02705 /*
02706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02707 %                                                                             %
02708 %                                                                             %
02709 %                                                                             %
02710 +   R e d u c e I m a g e C o l o r s                                         %
02711 %                                                                             %
02712 %                                                                             %
02713 %                                                                             %
02714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02715 %
02716 %  ReduceImageColors() repeatedly prunes the tree until the number of nodes
02717 %  with n2 > 0 is less than or equal to the maximum number of colors allowed
02718 %  in the output image.  On any given iteration over the tree, it selects
02719 %  those nodes whose E value is minimal for pruning and merges their
02720 %  color statistics upward. It uses a pruning threshold, Ep, to govern
02721 %  node selection as follows:
02722 %
02723 %    Ep = 0
02724 %    while number of nodes with (n2 > 0) > required maximum number of colors
02725 %      prune all nodes such that E <= Ep
02726 %      Set Ep to minimum E in remaining nodes
02727 %
02728 %  This has the effect of minimizing any quantization error when merging
02729 %  two nodes together.
02730 %
02731 %  When a node to be pruned has offspring, the pruning procedure invokes
02732 %  itself recursively in order to prune the tree from the leaves upward.
02733 %  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
02734 %  corresponding data in that node's parent.  This retains the pruned
02735 %  node's color characteristics for later averaging.
02736 %
02737 %  For each node, n2 pixels exist for which that node represents the
02738 %  smallest volume in RGB space containing those pixel's colors.  When n2
02739 %  > 0 the node will uniquely define a color in the output image. At the
02740 %  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
02741 %  the tree which represent colors present in the input image.
02742 %
02743 %  The other pixel count, n1, indicates the total number of colors
02744 %  within the cubic volume which the node represents.  This includes n1 -
02745 %  n2  pixels whose colors should be defined by nodes at a lower level in
02746 %  the tree.
02747 %
02748 %  The format of the ReduceImageColors method is:
02749 %
02750 %      ReduceImageColors(const Image *image,CubeInfo *cube_info)
02751 %
02752 %  A description of each parameter follows.
02753 %
02754 %    o image: the image.
02755 %
02756 %    o cube_info: A pointer to the Cube structure.
02757 %
02758 */
02759 static void ReduceImageColors(const Image *image,CubeInfo *cube_info)
02760 {
02761 #define ReduceImageTag  "Reduce/Image"
02762 
02763   MagickBooleanType
02764     proceed;
02765 
02766   MagickOffsetType
02767     offset;
02768 
02769   unsigned long
02770     span;
02771 
02772   cube_info->next_threshold=0.0;
02773   for (span=cube_info->colors; cube_info->colors > cube_info->maximum_colors; )
02774   {
02775     cube_info->pruning_threshold=cube_info->next_threshold;
02776     cube_info->next_threshold=cube_info->root->quantize_error-1;
02777     cube_info->colors=0;
02778     Reduce(image,cube_info,cube_info->root);
02779     offset=(MagickOffsetType) span-cube_info->colors;
02780     proceed=SetImageProgress(image,ReduceImageTag,offset,span-
02781       cube_info->maximum_colors+1);
02782     if (proceed == MagickFalse)
02783       break;
02784   }
02785 }
02786 
02787 /*
02788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02789 %                                                                             %
02790 %                                                                             %
02791 %                                                                             %
02792 %   R e m a p I m a g e                                                       %
02793 %                                                                             %
02794 %                                                                             %
02795 %                                                                             %
02796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02797 %
02798 %  RemapImage() replaces the colors of an image with the closest color from
02799 %  a reference image.
02800 %
02801 %  The format of the RemapImage method is:
02802 %
02803 %      MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
02804 %        Image *image,const Image *remap_image)
02805 %
02806 %  A description of each parameter follows:
02807 %
02808 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
02809 %
02810 %    o image: the image.
02811 %
02812 %    o remap_image: the reference image.
02813 %
02814 */
02815 MagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
02816   Image *image,const Image *remap_image)
02817 {
02818   CubeInfo
02819     *cube_info;
02820 
02821   MagickBooleanType
02822     status;
02823 
02824   /*
02825     Initialize color cube.
02826   */
02827   assert(image != (Image *) NULL);
02828   assert(image->signature == MagickSignature);
02829   if (image->debug != MagickFalse)
02830     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02831   assert(remap_image != (Image *) NULL);
02832   assert(remap_image->signature == MagickSignature);
02833   cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
02834     quantize_info->number_colors);
02835   if (cube_info == (CubeInfo *) NULL)
02836     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
02837       image->filename);
02838   status=ClassifyImageColors(cube_info,remap_image,&image->exception);
02839   if (status != MagickFalse)
02840     {
02841       /*
02842         Classify image colors from the reference image.
02843       */
02844       cube_info->quantize_info->number_colors=cube_info->colors;
02845       status=AssignImageColors(image,cube_info);
02846     }
02847   DestroyCubeInfo(cube_info);
02848   return(status);
02849 }
02850 
02851 /*
02852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02853 %                                                                             %
02854 %                                                                             %
02855 %                                                                             %
02856 %   R e m a p I m a g e s                                                     %
02857 %                                                                             %
02858 %                                                                             %
02859 %                                                                             %
02860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02861 %
02862 %  RemapImages() replaces the colors of a sequence of images with the
02863 %  closest color from a reference image.
02864 %
02865 %  The format of the RemapImage method is:
02866 %
02867 %      MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
02868 %        Image *images,Image *remap_image)
02869 %
02870 %  A description of each parameter follows:
02871 %
02872 %    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
02873 %
02874 %    o images: the image sequence.
02875 %
02876 %    o remap_image: the reference image.
02877 %
02878 */
02879 MagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
02880   Image *images,const Image *remap_image)
02881 {
02882   CubeInfo
02883     *cube_info;
02884 
02885   Image
02886     *image;
02887 
02888   MagickBooleanType
02889     status;
02890 
02891   assert(images != (Image *) NULL);
02892   assert(images->signature == MagickSignature);
02893   if (images->debug != MagickFalse)
02894     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
02895   image=images;
02896   if (remap_image == (Image *) NULL)
02897     {
02898       /*
02899         Create a global colormap for an image sequence.
02900       */
02901       status=QuantizeImages(quantize_info,images);
02902       return(status);
02903     }
02904   /*
02905     Classify image colors from the reference image.
02906   */
02907   cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
02908     quantize_info->number_colors);
02909   if (cube_info == (CubeInfo *) NULL)
02910     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
02911       image->filename);
02912   status=ClassifyImageColors(cube_info,remap_image,&image->exception);
02913   if (status != MagickFalse)
02914     {
02915       /*
02916         Classify image colors from the reference image.
02917       */
02918       cube_info->quantize_info->number_colors=cube_info->colors;
02919       image=images;
02920       for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
02921       {
02922         status=AssignImageColors(image,cube_info);
02923         if (status == MagickFalse)
02924           break;
02925       }
02926     }
02927   DestroyCubeInfo(cube_info);
02928   return(status);
02929 }
02930 
02931 /*
02932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02933 %                                                                             %
02934 %                                                                             %
02935 %                                                                             %
02936 %   S e t G r a y s c a l e I m a g e                                         %
02937 %                                                                             %
02938 %                                                                             %
02939 %                                                                             %
02940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02941 %
02942 %  SetGrayscaleImage() converts an image to a PseudoClass grayscale image.
02943 %
02944 %  The format of the SetGrayscaleImage method is:
02945 %
02946 %      MagickBooleanType SetGrayscaleImage(Image *image)
02947 %
02948 %  A description of each parameter follows:
02949 %
02950 %    o image: The image.
02951 %
02952 */
02953 
02954 #if defined(__cplusplus) || defined(c_plusplus)
02955 extern "C" {
02956 #endif
02957 
02958 static int IntensityCompare(const void *x,const void *y)
02959 {
02960   long
02961     intensity;
02962 
02963   PixelPacket
02964     *color_1,
02965     *color_2;
02966 
02967   color_1=(PixelPacket *) x;
02968   color_2=(PixelPacket *) y;
02969   intensity=PixelIntensityToQuantum(color_1)-(long)
02970     PixelIntensityToQuantum(color_2);
02971   return(intensity);
02972 }
02973 
02974 #if defined(__cplusplus) || defined(c_plusplus)
02975 }
02976 #endif
02977 
02978 static MagickBooleanType SetGrayscaleImage(Image *image)
02979 {
02980   ExceptionInfo
02981     *exception;
02982 
02983   long
02984     j,
02985     y;
02986 
02987   PixelPacket
02988     *colormap;
02989 
02990   long
02991     *colormap_index;
02992 
02993   register long
02994     i;
02995 
02996   MagickBooleanType
02997     status;
02998 
02999   CacheView
03000     *image_view;
03001 
03002   assert(image != (Image *) NULL);
03003   assert(image->signature == MagickSignature);
03004   if (image->type != GrayscaleType)
03005     (void) TransformImageColorspace(image,GRAYColorspace);
03006   colormap_index=(long *) AcquireQuantumMemory(MaxMap+1,
03007     sizeof(*colormap_index));
03008   if (colormap_index == (long *) NULL)
03009     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
03010       image->filename);
03011   if (image->storage_class != PseudoClass)
03012     {
03013       ExceptionInfo
03014         *exception;
03015 
03016       for (i=0; i <= (long) MaxMap; i++)
03017         colormap_index[i]=(-1);
03018       if (AcquireImageColormap(image,MaxMap+1) == MagickFalse)
03019         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
03020           image->filename);
03021       image->colors=0;
03022       status=MagickTrue;
03023       exception=(&image->exception);
03024       image_view=AcquireCacheView(image);
03025 #if defined(MAGICKCORE_OPENMP_SUPPORT)
03026   #pragma omp parallel for schedule(dynamic,4) shared(status)
03027 #endif
03028       for (y=0; y < (long) image->rows; y++)
03029       {
03030         register IndexPacket
03031           *__restrict indexes;
03032 
03033         register long
03034           x;
03035 
03036         register const PixelPacket
03037           *__restrict q;
03038 
03039         if (status == MagickFalse)
03040           continue;
03041         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
03042           exception);
03043         if (q == (PixelPacket *) NULL)
03044           {
03045             status=MagickFalse;
03046             continue;
03047           }
03048         indexes=GetCacheViewAuthenticIndexQueue(image_view);
03049         for (x=0; x < (long) image->columns; x++)
03050         {
03051           register unsigned long
03052             intensity;
03053 
03054           intensity=ScaleQuantumToMap(q->red);
03055           if (colormap_index[intensity] < 0)
03056             {
03057 #if defined(MAGICKCORE_OPENMP_SUPPORT)
03058     #pragma omp critical (MagickCore_SetGrayscaleImage)
03059 #endif
03060               if (colormap_index[intensity] < 0)
03061                 {
03062                   colormap_index[intensity]=(long) image->colors;
03063                   image->colormap[image->colors]=(*q);
03064                   image->colors++;
03065                }
03066             }
03067           indexes[x]=(IndexPacket) colormap_index[intensity];
03068           q++;
03069         }
03070         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
03071           status=MagickFalse;
03072       }
03073       image_view=DestroyCacheView(image_view);
03074     }
03075   for (i=0; i < (long) image->colors; i++)
03076     image->colormap[i].opacity=(unsigned short) i;
03077   qsort((void *) image->colormap,image->colors,sizeof(PixelPacket),
03078     IntensityCompare);
03079   colormap=(PixelPacket *) AcquireQuantumMemory(image->colors,
03080     sizeof(*colormap));
03081   if (colormap == (PixelPacket *) NULL)
03082     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
03083       image->filename);
03084   j=0;
03085   colormap[j]=image->colormap[0];
03086   for (i=0; i < (long) image->colors; i++)
03087   {
03088     if (IsSameColor(image,&colormap[j],&image->colormap[i]) == MagickFalse)
03089       {
03090         j++;
03091         colormap[j]=image->colormap[i];
03092       }
03093     colormap_index[(long) image->colormap[i].opacity]=j;
03094   }
03095   image->colors=(unsigned long) (j+1);
03096   image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
03097   image->colormap=colormap;
03098   status=MagickTrue;
03099   exception=(&image->exception);
03100   image_view=AcquireCacheView(image);
03101 #if defined(MAGICKCORE_OPENMP_SUPPORT)
03102   #pragma omp parallel for schedule(dynamic,4) shared(status)
03103 #endif
03104   for (y=0; y < (long) image->rows; y++)
03105   {
03106     register IndexPacket
03107       *__restrict indexes;
03108 
03109     register long
03110       x;
03111 
03112     register const PixelPacket
03113       *__restrict q;
03114 
03115     if (status == MagickFalse)
03116       continue;
03117     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
03118     if (q == (PixelPacket *) NULL)
03119       {
03120         status=MagickFalse;
03121         continue;
03122       }
03123     indexes=GetCacheViewAuthenticIndexQueue(image_view);
03124     for (x=0; x < (long) image->columns; x++)
03125       indexes[x]=(IndexPacket) colormap_index[ScaleQuantumToMap(indexes[x])];
03126     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
03127       status=MagickFalse;
03128   }
03129   image_view=DestroyCacheView(image_view);
03130   colormap_index=(long *) RelinquishMagickMemory(colormap_index);
03131   image->type=GrayscaleType;
03132   if (IsMonochromeImage(image,&image->exception) != MagickFalse)
03133     image->type=BilevelType;
03134   return(status);
03135 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1