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