13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           QQQ   U   U   AAA   N   N  TTTTT  IIIII   ZZZZZ  EEEEE            %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          Q   Q  U   U  A   A  NN  N    T      I        ZZ  E                %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          Q   Q  U   U  AAAAA  N N N    T      I      ZZZ   EEEEE            %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          Q  QQ  U   U  A   A  N  NN    T      I     ZZ     E                %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           QQQQ   UUU   A   A  N   N    T    IIIII   ZZZZZ  EEEEE            %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    MagickCore Methods to Reduce the Number of Unique Colors in an Image     %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                           Software Design                                   %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                Cristy                                       %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              July 1992                                      %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
207ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Realism in computer graphics typically requires using 24 bits/pixel to
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  generate an image.  Yet many graphic display devices do not contain the
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  amount of memory necessary to match the spatial and color resolution of
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the human eye.  The Quantize methods takes a 24 bit image and reduces
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the number of colors so it can be displayed on raster device with less
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  bits per pixel.  In most instances, the quantized image closely
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  resembles the original reference image.
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A reduction of colors in an image is also desirable for image
453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  transmission and real-time animation.
463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  QuantizeImage() takes a standard RGB or monochrome images and quantizes
483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  them down to some fixed number of colors.
493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  For purposes of color allocation, an image is a set of n pixels, where
513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  each pixel is a point in RGB space.  RGB space is a 3-dimensional
523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  vector space, and each pixel, Pi,  is defined by an ordered triple of
533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  red, green, and blue coordinates, (Ri, Gi, Bi).
543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Each primary color component (red, green, or blue) represents an
563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  intensity which varies linearly from 0 to a maximum value, Cmax, which
573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  corresponds to full saturation of that color.  Color allocation is
583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  defined over a domain consisting of the cube in RGB space with opposite
593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  vertices at (0,0,0) and (Cmax, Cmax, Cmax).  QUANTIZE requires Cmax =
603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  255.
613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The algorithm maps this domain onto a tree in which each node
633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  represents a cube within that domain.  In the following discussion
6418856c5df9f100c4fb1249790e86d79d860efb41cristy%  these cubes are defined by the coordinate of two opposite vertices (vertex
656a91c18a60eb2e0ab3c60293f759808e65bc2c49cristy%  nearest the origin in RGB space and the vertex farthest from the origin).
663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The tree's root node represents the entire domain, (0,0,0) through
683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  (Cmax,Cmax,Cmax).  Each lower level in the tree is generated by
693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  subdividing one node's cube into eight smaller cubes of equal size.
703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This corresponds to bisecting the parent cube with planes passing
713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  through the midpoints of each edge.
723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The basic algorithm operates in three phases: Classification,
743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Reduction, and Assignment.  Classification builds a color description
753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tree for the image.  Reduction collapses the tree until the number it
763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  represents, at most, the number of colors desired in the output image.
773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Assignment defines the output image's color map and sets each pixel's
783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color by restorage_class in the reduced tree.  Our goal is to minimize
793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the numerical discrepancies between the original colors and quantized
803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  colors (quantization error).
813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Classification begins by initializing a color description tree of
833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  sufficient depth to represent each possible input color in a leaf.
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  However, it is impractical to generate a fully-formed color description
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tree in the storage_class phase for realistic values of Cmax.  If
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  colors components in the input image are quantized to k-bit precision,
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  so that Cmax= 2k-1, the tree would need k levels below the root node to
883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  allow representing each possible input color in a leaf.  This becomes
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  prohibitive because the tree's total number of nodes is 1 +
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  sum(i=1, k, 8k).
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Initializes data structures for nodes only as they are needed;  (2)
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Chooses a maximum depth for the tree as a function of the desired
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  number of colors in the output image (currently log2(colormap size)).
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  For each pixel in the input image, storage_class scans downward from
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the root of the color description tree.  At each level of the tree it
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  identifies the single node which represents a cube in RGB space
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  containing the pixel's color.  It updates the following data for each
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  such node:
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    n1: Number of pixels whose color is contained in the RGB cube which
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    this node represents;
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    n2: Number of pixels whose color is not represented in a node at
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    lower depth in the tree;  initially,  n2 = 0 for all nodes except
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    leaves of the tree.
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    Sr, Sg, Sb: Sums of the red, green, and blue component values for all
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    pixels not classified at a lower depth. The combination of these sums
11309e81245d1499e747d676f1004992619e8d8d664cristy%    and n2 will ultimately characterize the mean color of a set of
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    pixels represented by this node.
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    E: the distance squared in RGB space between each pixel contained
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    within a node and the nodes' center.  This represents the
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    quantization error for a node.
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Reduction repeatedly prunes the tree until the number of nodes with n2
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  > 0 is less than or equal to the maximum number of colors allowed in
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the output image.  On any given iteration over the tree, it selects
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  those nodes whose E count is minimal for pruning and merges their color
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  statistics upward. It uses a pruning threshold, Ep, to govern node
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  selection as follows:
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    Ep = 0
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    while number of nodes with (n2 > 0) > required maximum number of colors
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      prune all nodes such that E <= Ep
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Set Ep to minimum E in remaining nodes
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This has the effect of minimizing any quantization error when merging
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two nodes together.
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  When a node to be pruned has offspring, the pruning procedure invokes
1363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  itself recursively in order to prune the tree from the leaves upward.
1373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
1383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  corresponding data in that node's parent.  This retains the pruned
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  node's color characteristics for later averaging.
1403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  For each node, n2 pixels exist for which that node represents the
1423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  smallest volume in RGB space containing those pixel's colors.  When n2
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  > 0 the node will uniquely define a color in the output image. At the
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the tree which represent colors present in the input image.
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The other pixel count, n1, indicates the total number of colors within
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the cubic volume which the node represents.  This includes n1 - n2
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pixels whose colors should be defined by nodes at a lower level in the
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tree.
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Assignment generates the output image from the pruned tree.  The output
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  image consists of two parts: (1)  A color map, which is an array of
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color descriptions (RGB triples) for each color present in the output
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  image;  (2)  A pixel array, which represents each pixel as an index
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  into the color map array.
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  First, the assignment phase makes one pass over the pruned color
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  description tree to establish the image's color map.  For each node
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color of all pixels that classify no lower than this node.  Each of
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  these colors becomes an entry in the color map.
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Finally,  the assignment phase reclassifies each pixel in the pruned
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tree to identify the deepest node containing the pixel's color.  The
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pixel's value in the pixel array becomes the index of this node's mean
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color in the color map.
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This method is based on a similar algorithm written by Paul Raveling.
1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1764c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
1774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/attribute.h"
1784c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h"
1794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color.h"
1804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h"
1814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colormap.h"
1824c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace.h"
183510d06a3f7063e91993e13d546d5685048248074cristy#include "MagickCore/colorspace-private.h"
1844c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h"
1854c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
1864c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
1874c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/histogram.h"
1884c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
1894c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
1904c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h"
1914c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
1924c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h"
1934c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h"
1944c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h"
1954c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
1961d1b10fb44a3606fdaf55e0998d50bee59401c17cristy#include "MagickCore/pixel-private.h"
1974c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h"
1984c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum.h"
1994c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
200ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h"
2014c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
2024c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/thread-private.h"
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Define declarations.
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
207e128751e49178d44b465609001a6b348fc5eab28cristy#if !defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define CacheShift  2
209e128751e49178d44b465609001a6b348fc5eab28cristy#else
210e128751e49178d44b465609001a6b348fc5eab28cristy#define CacheShift  3
211e128751e49178d44b465609001a6b348fc5eab28cristy#endif
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define ErrorQueueLength  16
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define MaxNodes  266817
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define MaxTreeDepth  8
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define NodesInAList  1920
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typdef declarations.
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2202392b4b33feea08c847a01411346fdce2bd6278cCristytypedef struct _DoublePixelInfo
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
222a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    red,
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    green,
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    blue,
2264c08aed51c5899665ade97263692328eea4af106cristy    alpha;
2272392b4b33feea08c847a01411346fdce2bd6278cCristy} DoublePixelInfo;
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristytypedef struct _NodeInfo
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  struct _NodeInfo
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *parent,
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *child[16];
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickSizeType
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_unique;
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2382392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    total_color;
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
241a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantize_error;
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
244bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    color_number,
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    id,
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    level;
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} NodeInfo;
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristytypedef struct _Nodes
2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *nodes;
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  struct _Nodes
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *next;
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} Nodes;
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristytypedef struct _CubeInfo
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *root;
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
264bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    colors,
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors;
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
268bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    transparent_index;
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickSizeType
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    transparent_pixels;
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2742392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    target;
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
277a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    distance,
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pruning_threshold,
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    next_threshold;
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
282bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    nodes,
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    free_nodes,
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    color_number;
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *next_node;
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Nodes
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *node_queue;
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
293a321eb7fb3b35eed694d0366543450d023900b5bcristy  MemoryInfo
294a321eb7fb3b35eed694d0366543450d023900b5bcristy    *memory_info;
295a321eb7fb3b35eed694d0366543450d023900b5bcristy
296bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cache;
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2992392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    error[ErrorQueueLength];
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
302a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    weights[ErrorQueueLength];
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantizeInfo
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantize_info;
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    associate_alpha;
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
311bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x,
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    y;
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
315bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    depth;
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickOffsetType
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset;
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickSizeType
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    span;
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} CubeInfo;
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Method prototypes.
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic CubeInfo
329bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  *GetCubeInfo(const QuantizeInfo *,const size_t,const size_t);
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic NodeInfo
332bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  *GetNodeInfo(CubeInfo *,const size_t,const size_t,NodeInfo *);
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
335018f07f7333b25743d0afff892450cebdb905c1acristy  AssignImageColors(Image *,CubeInfo *,ExceptionInfo *),
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ClassifyImageColors(CubeInfo *,const Image *,ExceptionInfo *),
3378a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  DitherImage(Image *,CubeInfo *,ExceptionInfo *),
338018f07f7333b25743d0afff892450cebdb905c1acristy  SetGrayscaleImage(Image *,ExceptionInfo *);
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
340bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic size_t
34106909863026300327af4ae61823f84976a179b9fcristy  DefineImageColormap(Image *,CubeInfo *,NodeInfo *);
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ClosestColor(const Image *,CubeInfo *,const NodeInfo *),
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DestroyCubeInfo(CubeInfo *),
346f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk  PruneLevel(CubeInfo *,const NodeInfo *),
347f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk  PruneToCubeDepth(CubeInfo *,const NodeInfo *),
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ReduceImageColors(const Image *,CubeInfo *);
3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A c q u i r e Q u a n t i z e I n f o                                     %
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AcquireQuantizeInfo() allocates the QuantizeInfo structure.
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AcquireQuantizeInfo method is:
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image_info: the image info.
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantizeInfo
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantize_info;
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
37773bd4a51b419e914565bdf204bf1540dc4c8ee26cristy  quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (quantize_info == (QuantizeInfo *) NULL)
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetQuantizeInfo(quantize_info);
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image_info != (ImageInfo *) NULL)
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      const char
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *option;
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
386cbda611068350bf4459f2dda1951f8823702e129cristy      quantize_info->dither_method=image_info->dither == MagickFalse ?
387cbda611068350bf4459f2dda1951f8823702e129cristy        NoDitherMethod : RiemersmaDitherMethod;
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      option=GetImageOption(image_info,"dither");
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (option != (const char *) NULL)
390042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy        quantize_info->dither_method=(DitherMethod) ParseCommandOption(
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          MagickDitherOptions,MagickFalse,option);
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantize_info->measure_error=image_info->verbose;
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(quantize_info);
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   A s s i g n I m a g e C o l o r s                                         %
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AssignImageColors() generates the output image from the pruned tree.  The
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output image consists of two parts: (1)  A color map, which is an array
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  of color descriptions (RGB triples) for each color present in the
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output image;  (2)  A pixel array, which represents each pixel as an
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  index into the color map array.
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  First, the assignment phase makes one pass over the pruned color
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  description tree to establish the image's color map.  For each node
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color of all pixels that classify no lower than this node.  Each of
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  these colors becomes an entry in the color map.
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Finally,  the assignment phase reclassifies each pixel in the pruned
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tree to identify the deepest node containing the pixel's color.  The
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pixel's value in the pixel array becomes the index of this node's mean
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color in the color map.
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AssignImageColors() method is:
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4374c08aed51c5899665ade97263692328eea4af106cristystatic inline void AssociateAlphaPixel(const Image *image,
4382392b4b33feea08c847a01411346fdce2bd6278cCristy  const CubeInfo *cube_info,const Quantum *pixel,DoublePixelInfo *alpha_pixel)
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
440a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha;
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->associate_alpha == MagickFalse) ||
44409e81245d1499e747d676f1004992619e8d8d664cristy      (GetPixelAlpha(image,pixel) == OpaqueAlpha))
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
446a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->red=(double) GetPixelRed(image,pixel);
447a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->green=(double) GetPixelGreen(image,pixel);
448a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->blue=(double) GetPixelBlue(image,pixel);
449a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->alpha=(double) GetPixelAlpha(image,pixel);
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return;
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
452a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixel));
4534c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->red=alpha*GetPixelRed(image,pixel);
4544c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->green=alpha*GetPixelGreen(image,pixel);
4554c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->blue=alpha*GetPixelBlue(image,pixel);
456a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  alpha_pixel->alpha=(double) GetPixelAlpha(image,pixel);
4574c08aed51c5899665ade97263692328eea4af106cristy}
4584c08aed51c5899665ade97263692328eea4af106cristy
459b0de93fdedaac769cb08e15b3ec176d4c9078907cristystatic inline void AssociateAlphaPixelInfo(const CubeInfo *cube_info,
4602392b4b33feea08c847a01411346fdce2bd6278cCristy  const PixelInfo *pixel,DoublePixelInfo *alpha_pixel)
4614c08aed51c5899665ade97263692328eea4af106cristy{
462a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
4634c08aed51c5899665ade97263692328eea4af106cristy    alpha;
4644c08aed51c5899665ade97263692328eea4af106cristy
4654c08aed51c5899665ade97263692328eea4af106cristy  if ((cube_info->associate_alpha == MagickFalse) ||
4664c08aed51c5899665ade97263692328eea4af106cristy      (pixel->alpha == OpaqueAlpha))
4674c08aed51c5899665ade97263692328eea4af106cristy    {
468a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->red=(double) pixel->red;
469a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->green=(double) pixel->green;
470a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->blue=(double) pixel->blue;
471a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha_pixel->alpha=(double) pixel->alpha;
4724c08aed51c5899665ade97263692328eea4af106cristy      return;
4734c08aed51c5899665ade97263692328eea4af106cristy    }
474a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  alpha=(double) (QuantumScale*pixel->alpha);
4754c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->red=alpha*pixel->red;
4764c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->green=alpha*pixel->green;
4774c08aed51c5899665ade97263692328eea4af106cristy  alpha_pixel->blue=alpha*pixel->blue;
478a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  alpha_pixel->alpha=(double) pixel->alpha;
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
481bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic inline size_t ColorToNodeId(const CubeInfo *cube_info,
4822392b4b33feea08c847a01411346fdce2bd6278cCristy  const DoublePixelInfo *pixel,size_t index)
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
484bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    id;
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4876f7e04238c57b6c78a9b4bda89da594775947667cristy  id=(size_t) (((ScaleQuantumToChar(ClampPixel(pixel->red)) >> index) & 0x01) |
4886f7e04238c57b6c78a9b4bda89da594775947667cristy    ((ScaleQuantumToChar(ClampPixel(pixel->green)) >> index) & 0x01) << 1 |
4896f7e04238c57b6c78a9b4bda89da594775947667cristy    ((ScaleQuantumToChar(ClampPixel(pixel->blue)) >> index) & 0x01) << 2);
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info->associate_alpha != MagickFalse)
4916f7e04238c57b6c78a9b4bda89da594775947667cristy    id|=((ScaleQuantumToChar(ClampPixel(pixel->alpha)) >> index) & 0x1) << 3;
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(id);
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
495e0e988184bb8d87677bcf24920aa9bbf15a3236fdirkstatic MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info,
496e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk  ExceptionInfo *exception)
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
498e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk#define AssignImageTag  "Assign/Image"
499e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk
500e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk  ssize_t
501e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk    y;
502e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Allocate image colormap.
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (cube_info->quantize_info->colorspace != CMYKColorspace))
5080b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy    (void) TransformImageColorspace(image,cube_info->quantize_info->colorspace,
5090b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      exception);
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
5113d9f5ba107b160e1819bb6baeeb3a9f521e9f450cristy    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
5120b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      (void) TransformImageColorspace(image,sRGBColorspace,exception);
513018f07f7333b25743d0afff892450cebdb905c1acristy  if (AcquireImageColormap(image,cube_info->colors,exception) == MagickFalse)
514e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
515e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk      image->filename);;
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->colors=0;
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->transparent_pixels=0;
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->transparent_index=(-1);
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) DefineImageColormap(image,cube_info,cube_info->root);
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Create a reduced color image.
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
523f2a82ee6e25411cb280db708ff26ab55cece1945cristy  if (cube_info->quantize_info->dither_method != NoDitherMethod)
5248a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy    (void) DitherImage(image,cube_info,exception);
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
527e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      CacheView
528e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        *image_view;
529e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
530e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      MagickBooleanType
531e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        status;
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
533e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      status=MagickTrue;
53446ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy      image_view=AcquireAuthenticCacheView(image,exception);
535e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
536ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy      #pragma omp parallel for schedule(static,4) shared(status) \
5375e6b259130f9dbe0da4666f734937017babe573acristy        magick_threads(image,image,image->rows,1)
538e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy#endif
539bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0; y < (ssize_t) image->rows; y++)
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
541e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        CubeInfo
542e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          cube;
543e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
5444c08aed51c5899665ade97263692328eea4af106cristy        register Quantum
54505d2ff7ebf21f659f5b11e45afb294e152f4330cdirk          *magick_restrict q;
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
547e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        register ssize_t
548e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          x;
549e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
550e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        ssize_t
551e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          count;
552e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
553e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        if (status == MagickFalse)
554e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          continue;
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          exception);
557acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
558e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          {
559e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            status=MagickFalse;
560e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            continue;
561e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          }
562e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        cube=(*cube_info);
563bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0; x < (ssize_t) image->columns; x+=count)
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5652392b4b33feea08c847a01411346fdce2bd6278cCristy          DoublePixelInfo
566e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            pixel;
567e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
568e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          register const NodeInfo
569e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            *node_info;
570e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
571e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          register ssize_t
572e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            i;
573e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
574e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          size_t
575e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            id,
576e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            index;
577e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Identify the deepest node containing the pixel's color.
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
581bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (count=1; (x+count) < (ssize_t) image->columns; count++)
5824c08aed51c5899665ade97263692328eea4af106cristy          {
583101ab708b0574518ac5715da4d3915400e9df79acristy            PixelInfo
5844c08aed51c5899665ade97263692328eea4af106cristy              packet;
5854c08aed51c5899665ade97263692328eea4af106cristy
586101ab708b0574518ac5715da4d3915400e9df79acristy            GetPixelInfoPixel(image,q+count*GetPixelChannels(image),&packet);
5874c08aed51c5899665ade97263692328eea4af106cristy            if (IsPixelEquivalent(image,q,&packet) == MagickFalse)
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
5894c08aed51c5899665ade97263692328eea4af106cristy          }
5904c08aed51c5899665ade97263692328eea4af106cristy          AssociateAlphaPixel(image,&cube,q,&pixel);
591e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          node_info=cube.root;
592bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
594e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            id=ColorToNodeId(&cube,&pixel,index);
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (node_info->child[id] == (NodeInfo *) NULL)
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            node_info=node_info->child[id];
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Find closest color among siblings and their children.
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
602e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          cube.target=pixel;
60309e81245d1499e747d676f1004992619e8d8d664cristy          cube.distance=(double) (4.0*(QuantumRange+1.0)*(QuantumRange+1.0)+
60409e81245d1499e747d676f1004992619e8d8d664cristy            1.0);
605e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          ClosestColor(image,&cube,node_info->parent);
606e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          index=cube.color_number;
607bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (i=0; i < (ssize_t) count; i++)
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (image->storage_class == PseudoClass)
6104c08aed51c5899665ade97263692328eea4af106cristy              SetPixelIndex(image,(Quantum) index,q);
611e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            if (cube.quantize_info->measure_error == MagickFalse)
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              {
613e42f658533644aecb733785ffd91b286d6778deacristy                SetPixelRed(image,ClampToQuantum(
614e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[index].red),q);
615e42f658533644aecb733785ffd91b286d6778deacristy                SetPixelGreen(image,ClampToQuantum(
616e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[index].green),q);
617e42f658533644aecb733785ffd91b286d6778deacristy                SetPixelBlue(image,ClampToQuantum(
618e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[index].blue),q);
619e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy                if (cube.associate_alpha != MagickFalse)
620e42f658533644aecb733785ffd91b286d6778deacristy                  SetPixelAlpha(image,ClampToQuantum(
621e42f658533644aecb733785ffd91b286d6778deacristy                    image->colormap[index].alpha),q);
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              }
623ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy            q+=GetPixelChannels(image);
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
627e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          status=MagickFalse;
628e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        if (image->progress_monitor != (MagickProgressMonitor) NULL)
629e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          {
630e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            MagickBooleanType
631e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy              proceed;
632e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
633e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
634e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            #pragma omp critical (MagickCore_AssignImageColors)
635e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy#endif
636e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
637e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy              image->rows);
638e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            if (proceed == MagickFalse)
639e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy              status=MagickFalse;
640e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          }
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image_view=DestroyCacheView(image_view);
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
644e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk  if (cube_info->quantize_info->measure_error != MagickFalse)
645e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk    (void) GetImageQuantizeError(image,exception);
646e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk  if ((cube_info->quantize_info->number_colors == 2) &&
647e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk      (cube_info->quantize_info->colorspace == GRAYColorspace))
648e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk    {
649e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk      double
650e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk        intensity;
651e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk
652e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk      /*
653e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk        Monochrome image.
654e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk      */
6550b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      intensity=0.0;
656d95b61923cb821069f16689669f2c2a5a94fc960Cristy      if ((image->colors > 1) &&
657d95b61923cb821069f16689669f2c2a5a94fc960Cristy          (GetPixelInfoLuma(image->colormap+0) >
658d95b61923cb821069f16689669f2c2a5a94fc960Cristy           GetPixelInfoLuma(image->colormap+1)))
6590b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy        intensity=(double) QuantumRange;
6600b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      image->colormap[0].red=intensity;
6610b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      image->colormap[0].green=intensity;
6620b0d73548a9ac52da461ba38ac114dbb2a7828dcCristy      image->colormap[0].blue=intensity;
663d95b61923cb821069f16689669f2c2a5a94fc960Cristy      if (image->colors > 1)
664d95b61923cb821069f16689669f2c2a5a94fc960Cristy        {
665d95b61923cb821069f16689669f2c2a5a94fc960Cristy          image->colormap[1].red=(double) QuantumRange-intensity;
666d95b61923cb821069f16689669f2c2a5a94fc960Cristy          image->colormap[1].green=(double) QuantumRange-intensity;
667d95b61923cb821069f16689669f2c2a5a94fc960Cristy          image->colormap[1].blue=(double) QuantumRange-intensity;
668d95b61923cb821069f16689669f2c2a5a94fc960Cristy        }
669e0e988184bb8d87677bcf24920aa9bbf15a3236fdirk    }
670ea1a8aa04a9fe1500104284407c1cc06d20da699cristy  (void) SyncImage(image,exception);
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (cube_info->quantize_info->colorspace != CMYKColorspace))
673c511e881bdb2adc9c87173f8c3a6a747a96dbabdcristy    (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   C l a s s i f y I m a g e C o l o r s                                     %
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ClassifyImageColors() begins by initializing a color description tree
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  of sufficient depth to represent each possible input color in a leaf.
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  However, it is impractical to generate a fully-formed color
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  description tree in the storage_class phase for realistic values of
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Cmax.  If colors components in the input image are quantized to k-bit
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  precision, so that Cmax= 2k-1, the tree would need k levels below the
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  root node to allow representing each possible input color in a leaf.
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This becomes prohibitive because the tree's total number of nodes is
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  1 + sum(i=1,k,8k).
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Initializes data structures for nodes only as they are needed;  (2)
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Chooses a maximum depth for the tree as a function of the desired
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  number of colors in the output image (currently log2(colormap size)).
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  For each pixel in the input image, storage_class scans downward from
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the root of the color description tree.  At each level of the tree it
7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  identifies the single node which represents a cube in RGB space
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  containing It updates the following data for each such node:
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    n1 : Number of pixels whose color is contained in the RGB cube
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    which this node represents;
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    n2 : Number of pixels whose color is not represented in a node at
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    lower depth in the tree;  initially,  n2 = 0 for all nodes except
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    leaves of the tree.
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    Sr, Sg, Sb : Sums of the red, green, and blue component values for
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    all pixels not classified at a lower depth. The combination of
71809e81245d1499e747d676f1004992619e8d8d664cristy%    these sums and n2 will ultimately characterize the mean color of a
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    set of pixels represented by this node.
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    E: the distance squared in RGB space between each pixel contained
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    within a node and the nodes' center.  This represents the quantization
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    error for a node.
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ClassifyImageColors() method is:
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const Image *image,ExceptionInfo *exception)
7293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline void SetAssociatedAlpha(const Image *image,CubeInfo *cube_info)
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    associate_alpha;
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
74309e81245d1499e747d676f1004992619e8d8d664cristy  associate_alpha=image->alpha_trait == BlendPixelTrait ? MagickTrue :
744b0a657e13c4aefba39c51292005427b47277869dcristy    MagickFalse;
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->quantize_info->number_colors == 2) &&
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (cube_info->quantize_info->colorspace == GRAYColorspace))
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    associate_alpha=MagickFalse;
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->associate_alpha=associate_alpha;
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const Image *image,ExceptionInfo *exception)
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define ClassifyImageTag  "Classify/Image"
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
756c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
757c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
758c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
7592392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
7602392b4b33feea08c847a01411346fdce2bd6278cCristy    error,
7612392b4b33feea08c847a01411346fdce2bd6278cCristy    mid,
7622392b4b33feea08c847a01411346fdce2bd6278cCristy    midpoint,
7632392b4b33feea08c847a01411346fdce2bd6278cCristy    pixel;
7642392b4b33feea08c847a01411346fdce2bd6278cCristy
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    proceed;
7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
768a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bisect;
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *node_info;
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
775ecc31b159fd21093c91198f7fa26072d288e5230cristy    count,
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    id,
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    index,
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    level;
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
780ecc31b159fd21093c91198f7fa26072d288e5230cristy  ssize_t
781ecc31b159fd21093c91198f7fa26072d288e5230cristy    y;
782ecc31b159fd21093c91198f7fa26072d288e5230cristy
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Classify the first cube_info->maximum_colors colors to a tree depth of 8.
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetAssociatedAlpha(image,cube_info);
7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (cube_info->quantize_info->colorspace != CMYKColorspace))
7893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) TransformImageColorspace((Image *) image,
790e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy      cube_info->quantize_info->colorspace,exception);
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
7923d9f5ba107b160e1819bb6baeeb3a9f521e9f450cristy    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
793c511e881bdb2adc9c87173f8c3a6a747a96dbabdcristy      (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
794a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  midpoint.red=(double) QuantumRange/2.0;
795a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  midpoint.green=(double) QuantumRange/2.0;
796a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  midpoint.blue=(double) QuantumRange/2.0;
797a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  midpoint.alpha=(double) QuantumRange/2.0;
7984c08aed51c5899665ade97263692328eea4af106cristy  error.alpha=0.0;
79946ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireVirtualCacheView(image,exception);
800bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
8013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
8024c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
80305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
8043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
805bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register ssize_t
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x;
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
8094c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (cube_info->nodes > MaxNodes)
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Prune one level if the color tree is too large.
8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
816f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk        PruneLevel(cube_info,cube_info->root);
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->depth--;
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
819bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Start at the root and descend the color cube tree.
8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
824bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
8254c08aed51c5899665ade97263692328eea4af106cristy      {
826101ab708b0574518ac5715da4d3915400e9df79acristy        PixelInfo
8274c08aed51c5899665ade97263692328eea4af106cristy          packet;
8284c08aed51c5899665ade97263692328eea4af106cristy
829101ab708b0574518ac5715da4d3915400e9df79acristy        GetPixelInfoPixel(image,p+count*GetPixelChannels(image),&packet);
8304c08aed51c5899665ade97263692328eea4af106cristy        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
8324c08aed51c5899665ade97263692328eea4af106cristy      }
8334c08aed51c5899665ade97263692328eea4af106cristy      AssociateAlphaPixel(image,cube_info,p,&pixel);
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      index=MaxTreeDepth-1;
835a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      bisect=((double) QuantumRange+1.0)/2.0;
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mid=midpoint;
8373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      node_info=cube_info->root;
8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (level=1; level <= MaxTreeDepth; level++)
8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
840b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        double
841b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          distance;
842b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        bisect*=0.5;
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        id=ColorToNodeId(cube_info,&pixel,index);
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.red+=(id & 1) != 0 ? bisect : -bisect;
8463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.green+=(id & 2) != 0 ? bisect : -bisect;
8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
8484c08aed51c5899665ade97263692328eea4af106cristy        mid.alpha+=(id & 8) != 0 ? bisect : -bisect;
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (node_info->child[id] == (NodeInfo *) NULL)
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            /*
8523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              Set colors of new node to contain pixel.
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            */
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (node_info->child[id] == (NodeInfo *) NULL)
856ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy              {
857ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                (void) ThrowMagickException(exception,GetMagickModule(),
858ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
859ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                  image->filename);
860ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                continue;
861ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy              }
8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (level == MaxTreeDepth)
8633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              cube_info->colors++;
8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Approximate the quantization error represented by this node.
8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        node_info=node_info->child[id];
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.red=QuantumScale*(pixel.red-mid.red);
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.green=QuantumScale*(pixel.green-mid.green);
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.blue=QuantumScale*(pixel.blue-mid.blue);
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (cube_info->associate_alpha != MagickFalse)
8734c08aed51c5899665ade97263692328eea4af106cristy          error.alpha=QuantumScale*(pixel.alpha-mid.alpha);
874b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        distance=(double) (error.red*error.red+error.green*error.green+
875b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          error.blue*error.blue+error.alpha*error.alpha);
8763667479b817685c0289edd0fd597d07bc2c6b462dirk        if (IsNaN(distance))
877b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          distance=0.0;
878b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        node_info->quantize_error+=count*sqrt(distance);
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->root->quantize_error+=node_info->quantize_error;
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        index--;
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Sum RGB for this leaf for later derivation of the mean cube color.
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      node_info->number_unique+=count;
8861aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.red+=count*QuantumScale*ClampPixel(pixel.red);
8871aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.green+=count*QuantumScale*ClampPixel(pixel.green);
8881aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.blue+=count*QuantumScale*ClampPixel(pixel.blue);
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->associate_alpha != MagickFalse)
890146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy        node_info->total_color.alpha+=count*QuantumScale*
891146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy          ClampPixel(pixel.alpha);
892146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy      else
893146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy        node_info->total_color.alpha+=count*QuantumScale*
894146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy          ClampPixel(OpaqueAlpha);
895ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=count*GetPixelChannels(image);
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (cube_info->colors > cube_info->maximum_colors)
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
899f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk        PruneToCubeDepth(cube_info,cube_info->root);
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
902cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
903cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy      image->rows);
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (proceed == MagickFalse)
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
907bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y++; y < (ssize_t) image->rows; y++)
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
9094c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
91005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
912bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register ssize_t
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x;
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
9164c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (cube_info->nodes > MaxNodes)
9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Prune one level if the color tree is too large.
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
923f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk        PruneLevel(cube_info,cube_info->root);
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->depth--;
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
926bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
9283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Start at the root and descend the color cube tree.
9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
931bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
9324c08aed51c5899665ade97263692328eea4af106cristy      {
933101ab708b0574518ac5715da4d3915400e9df79acristy        PixelInfo
9344c08aed51c5899665ade97263692328eea4af106cristy          packet;
9354c08aed51c5899665ade97263692328eea4af106cristy
936101ab708b0574518ac5715da4d3915400e9df79acristy        GetPixelInfoPixel(image,p+count*GetPixelChannels(image),&packet);
9374c08aed51c5899665ade97263692328eea4af106cristy        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
9394c08aed51c5899665ade97263692328eea4af106cristy      }
9404c08aed51c5899665ade97263692328eea4af106cristy      AssociateAlphaPixel(image,cube_info,p,&pixel);
9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      index=MaxTreeDepth-1;
942a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      bisect=((double) QuantumRange+1.0)/2.0;
9433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mid=midpoint;
9443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      node_info=cube_info->root;
9453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (level=1; level <= cube_info->depth; level++)
9463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
947b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        double
948b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          distance;
949b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy
9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        bisect*=0.5;
9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        id=ColorToNodeId(cube_info,&pixel,index);
9523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.red+=(id & 1) != 0 ? bisect : -bisect;
9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.green+=(id & 2) != 0 ? bisect : -bisect;
9543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
9554c08aed51c5899665ade97263692328eea4af106cristy        mid.alpha+=(id & 8) != 0 ? bisect : -bisect;
9563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (node_info->child[id] == (NodeInfo *) NULL)
9573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
9583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            /*
9593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              Set colors of new node to contain pixel.
9603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            */
9613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
9623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (node_info->child[id] == (NodeInfo *) NULL)
963ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy              {
964ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                (void) ThrowMagickException(exception,GetMagickModule(),
965ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                  ResourceLimitError,"MemoryAllocationFailed","%s",
966ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                  image->filename);
967ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy                continue;
968ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy              }
9693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (level == cube_info->depth)
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              cube_info->colors++;
9713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
9723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
9733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Approximate the quantization error represented by this node.
9743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        node_info=node_info->child[id];
9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.red=QuantumScale*(pixel.red-mid.red);
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.green=QuantumScale*(pixel.green-mid.green);
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        error.blue=QuantumScale*(pixel.blue-mid.blue);
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (cube_info->associate_alpha != MagickFalse)
9804c08aed51c5899665ade97263692328eea4af106cristy          error.alpha=QuantumScale*(pixel.alpha-mid.alpha);
981b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        distance=(double) (error.red*error.red+error.green*error.green+
982b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          error.blue*error.blue+error.alpha*error.alpha);
983b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        if (IsNaN(distance) != MagickFalse)
984b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy          distance=0.0;
985b4d27c3dba1d142ba3eade4ba8067ba33756eff3cristy        node_info->quantize_error+=count*sqrt(distance);
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->root->quantize_error+=node_info->quantize_error;
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        index--;
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Sum RGB for this leaf for later derivation of the mean cube color.
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      node_info->number_unique+=count;
9931aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.red+=count*QuantumScale*ClampPixel(pixel.red);
9941aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.green+=count*QuantumScale*ClampPixel(pixel.green);
9951aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy      node_info->total_color.blue+=count*QuantumScale*ClampPixel(pixel.blue);
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->associate_alpha != MagickFalse)
997146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy        node_info->total_color.alpha+=count*QuantumScale*
998146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy          ClampPixel(pixel.alpha);
999146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy      else
1000146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy        node_info->total_color.alpha+=count*QuantumScale*
1001146c48281b69f6084ef8c44ac08fb5edb8aa564aCristy          ClampPixel(OpaqueAlpha);
1002ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=count*GetPixelChannels(image);
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1004cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
1005cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy      image->rows);
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (proceed == MagickFalse)
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (cube_info->quantize_info->colorspace != CMYKColorspace))
1012c511e881bdb2adc9c87173f8c3a6a747a96dbabdcristy    (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
1013ac21aa22bfdf266fe328145f85d72e804f7d4c54cristy  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   C l o n e Q u a n t i z e I n f o                                         %
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  CloneQuantizeInfo() makes a duplicate of the given quantize info structure,
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  or if quantize info is NULL, a new one.
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the CloneQuantizeInfo method is:
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o clone_info: Method CloneQuantizeInfo returns a duplicate of the given
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      quantize info, or if image info is NULL a new one.
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: a structure of type info.
10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantizeInfo
10453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *clone_info;
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
104773bd4a51b419e914565bdf204bf1540dc4c8ee26cristy  clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (clone_info == (QuantizeInfo *) NULL)
10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
10503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetQuantizeInfo(clone_info);
10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (quantize_info == (QuantizeInfo *) NULL)
10523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(clone_info);
10533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  clone_info->number_colors=quantize_info->number_colors;
10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  clone_info->tree_depth=quantize_info->tree_depth;
10553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  clone_info->dither_method=quantize_info->dither_method;
10563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  clone_info->colorspace=quantize_info->colorspace;
10573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  clone_info->measure_error=quantize_info->measure_error;
10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(clone_info);
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   C l o s e s t C o l o r                                                   %
10673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ClosestColor() traverses the color cube tree at a particular node and
10733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  determines which colormap entry best represents the input color.
10743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ClosestColor method is:
10763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      void ClosestColor(const Image *image,CubeInfo *cube_info,
10783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const NodeInfo *node_info)
10793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
10813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
10833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
10853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: the address of a structure of type NodeInfo which points to a
10873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      node in the color cube tree that is to be pruned.
10883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10903ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void ClosestColor(const Image *image,CubeInfo *cube_info,
10913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const NodeInfo *node_info)
10923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1093bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
10943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1096bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
1103bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ClosestColor(image,cube_info,node_info->child[i]);
11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (node_info->number_unique != 0)
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1108a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      double
11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel;
11103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1111a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      register double
11123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha,
11133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        beta,
11143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        distance;
11153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11162392b4b33feea08c847a01411346fdce2bd6278cCristy      register DoublePixelInfo
11172392b4b33feea08c847a01411346fdce2bd6278cCristy        *magick_restrict q;
11182392b4b33feea08c847a01411346fdce2bd6278cCristy
1119101ab708b0574518ac5715da4d3915400e9df79acristy      register PixelInfo
112005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk        *magick_restrict p;
11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Determine if this color is "closest".
11243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=image->colormap+node_info->color_number;
11263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=(&cube_info->target);
11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      alpha=1.0;
11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      beta=1.0;
1129847620f4bd8fefe706e29da8299ffb6f60124915cristy      if (cube_info->associate_alpha != MagickFalse)
11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1131a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          alpha=(double) (QuantumScale*p->alpha);
1132a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          beta=(double) (QuantumScale*q->alpha);
11333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
11344c08aed51c5899665ade97263692328eea4af106cristy      pixel=alpha*p->red-beta*q->red;
11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      distance=pixel*pixel;
113636fbc3b1d229433c8558116b1c526ed68d61ab5ecristy      if (distance <= cube_info->distance)
11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
11384c08aed51c5899665ade97263692328eea4af106cristy          pixel=alpha*p->green-beta*q->green;
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          distance+=pixel*pixel;
114036fbc3b1d229433c8558116b1c526ed68d61ab5ecristy          if (distance <= cube_info->distance)
11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
11424c08aed51c5899665ade97263692328eea4af106cristy              pixel=alpha*p->blue-beta*q->blue;
11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              distance+=pixel*pixel;
114436fbc3b1d229433c8558116b1c526ed68d61ab5ecristy              if (distance <= cube_info->distance)
11453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                {
114629e8af76f4361aa375e375cdd4545536cd9b9ac9Cristy                  if (cube_info->associate_alpha != MagickFalse)
114729e8af76f4361aa375e375cdd4545536cd9b9ac9Cristy                    {
114829e8af76f4361aa375e375cdd4545536cd9b9ac9Cristy                      pixel=p->alpha-q->alpha;
114929e8af76f4361aa375e375cdd4545536cd9b9ac9Cristy                      distance+=pixel*pixel;
115029e8af76f4361aa375e375cdd4545536cd9b9ac9Cristy                    }
1151c408040951108ca302314a937ac064c3f12f7502cristy                  if (distance <= cube_info->distance)
11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                    {
11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                      cube_info->distance=distance;
11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                      cube_info->color_number=node_info->color_number;
11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                    }
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                }
11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
11593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   C o m p r e s s I m a g e C o l o r m a p                                 %
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  CompressImageColormap() compresses an image colormap by removing any
11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  duplicate or unused color entries.
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the CompressImageColormap method is:
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1178018f07f7333b25743d0afff892450cebdb905c1acristy%      MagickBooleanType CompressImageColormap(Image *image,
1179018f07f7333b25743d0afff892450cebdb905c1acristy%        ExceptionInfo *exception)
11803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
11823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
11843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1185018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
1186018f07f7333b25743d0afff892450cebdb905c1acristy%
11873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1188018f07f7333b25743d0afff892450cebdb905c1acristyMagickExport MagickBooleanType CompressImageColormap(Image *image,
1189018f07f7333b25743d0afff892450cebdb905c1acristy  ExceptionInfo *exception)
11903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantizeInfo
11923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantize_info;
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
1195e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1198ab4f0bb4e2c2d3e3e61408499755fa710f15e18fdirk  if (image->storage_class != PseudoClass)
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetQuantizeInfo(&quantize_info);
12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info.number_colors=image->colors;
12023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info.tree_depth=MaxTreeDepth;
1203018f07f7333b25743d0afff892450cebdb905c1acristy  return(QuantizeImage(&quantize_info,image,exception));
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   D e f i n e I m a g e C o l o r m a p                                     %
12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DefineImageColormap() traverses the color cube tree and notes each colormap
12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  entry.  A colormap entry is any node in the color cube tree where the
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  of unique colors is not zero.  DefineImageColormap() returns the number of
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  colors in the image colormap.
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DefineImageColormap method is:
12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1224bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      size_t DefineImageColormap(Image *image,CubeInfo *cube_info,
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        NodeInfo *node_info)
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: the address of a structure of type NodeInfo which points to a
12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      node in the color cube tree that is to be pruned.
12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1237bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic size_t DefineImageColormap(Image *image,CubeInfo *cube_info,
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo *node_info)
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1240bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1243bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
12493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
1250bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
1252cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy      (void) DefineImageColormap(image,cube_info,node_info->child[i]);
12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (node_info->number_unique != 0)
12543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1255a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      register double
12563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha;
12573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1258101ab708b0574518ac5715da4d3915400e9df79acristy      register PixelInfo
125905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk        *magick_restrict q;
12603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
12623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Colormap entry is defined by the mean color in this cube.
12633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
12643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=image->colormap+image->colors;
1265a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy      alpha=(double) ((MagickOffsetType) node_info->number_unique);
12663e3ec3afbb0782697f201cbe30a56794c10dc7efcristy      alpha=PerceptibleReciprocal(alpha);
12673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->associate_alpha == MagickFalse)
12683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
12691aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy          q->red=(double) ClampToQuantum(alpha*QuantumRange*
12701aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy            node_info->total_color.red);
12711aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy          q->green=(double) ClampToQuantum(alpha*QuantumRange*
12721aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy            node_info->total_color.green);
12731aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy          q->blue=(double) ClampToQuantum(alpha*QuantumRange*
12741aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy            node_info->total_color.blue);
12751aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy          q->alpha=(double) OpaqueAlpha;
12763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
12773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
12783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1279a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          double
12803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            opacity;
12813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12821aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy          opacity=(double) (alpha*QuantumRange*node_info->total_color.alpha);
128309e81245d1499e747d676f1004992619e8d8d664cristy          q->alpha=(double) ClampToQuantum(opacity);
12844c08aed51c5899665ade97263692328eea4af106cristy          if (q->alpha == OpaqueAlpha)
12853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
12861aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->red=(double) ClampToQuantum(alpha*QuantumRange*
12871aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.red);
12881aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->green=(double) ClampToQuantum(alpha*QuantumRange*
12891aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.green);
12901aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->blue=(double) ClampToQuantum(alpha*QuantumRange*
12911aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.blue);
12923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
12933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
12943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
1295a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy              double
12963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                gamma;
12973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1298a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy              gamma=(double) (QuantumScale*q->alpha);
12993e3ec3afbb0782697f201cbe30a56794c10dc7efcristy              gamma=PerceptibleReciprocal(gamma);
13001aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->red=(double) ClampToQuantum(alpha*gamma*QuantumRange*
13011aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.red);
13021aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->green=(double) ClampToQuantum(alpha*gamma*QuantumRange*
13031aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.green);
13041aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy              q->blue=(double) ClampToQuantum(alpha*gamma*QuantumRange*
13051aeeff3ee13feff2b958a5019723a9d6d2ca09cfcristy                node_info->total_color.blue);
13063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (node_info->number_unique > cube_info->transparent_pixels)
13073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                {
13083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  cube_info->transparent_pixels=node_info->number_unique;
1309bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy                  cube_info->transparent_index=(ssize_t) image->colors;
13103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                }
13113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
13123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
13133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      node_info->color_number=image->colors++;
13143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
13153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(image->colors);
13163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
13173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
13193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   D e s t r o y C u b e I n f o                                             %
13243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyCubeInfo() deallocates memory associated with an image.
13303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyCubeInfo method is:
13323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      DestroyCubeInfo(CubeInfo *cube_info)
13343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
13363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: the address of a structure of type CubeInfo.
13383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
13403ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void DestroyCubeInfo(CubeInfo *cube_info)
13413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
13423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register Nodes
13433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *nodes;
13443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
13463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Release color cube tree storage.
13473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
13483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  do
13493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
13503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    nodes=cube_info->node_queue->next;
13513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->node_queue->nodes=(NodeInfo *) RelinquishMagickMemory(
13523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->node_queue->nodes);
13533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->node_queue=(Nodes *) RelinquishMagickMemory(
13543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->node_queue);
13553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->node_queue=nodes;
13563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  } while (cube_info->node_queue != (Nodes *) NULL);
1357a321eb7fb3b35eed694d0366543450d023900b5bcristy  if (cube_info->memory_info != (MemoryInfo *) NULL)
1358a321eb7fb3b35eed694d0366543450d023900b5bcristy    cube_info->memory_info=RelinquishVirtualMemory(cube_info->memory_info);
13593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->quantize_info=DestroyQuantizeInfo(cube_info->quantize_info);
13603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info=(CubeInfo *) RelinquishMagickMemory(cube_info);
13613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
13623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
13643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   D e s t r o y Q u a n t i z e I n f o                                     %
13693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyQuantizeInfo() deallocates memory associated with an QuantizeInfo
13753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  structure.
13763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyQuantizeInfo method is:
13783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
13803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
13823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
13843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
13863ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
13873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
13883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
13893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(quantize_info != (QuantizeInfo *) NULL);
1390e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(quantize_info->signature == MagickCoreSignature);
1391e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  quantize_info->signature=(~MagickCoreSignature);
13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info=(QuantizeInfo *) RelinquishMagickMemory(quantize_info);
13933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(quantize_info);
13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
13973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   D i t h e r I m a g e                                                     %
14023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DitherImage() distributes the difference between an original image and
14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the corresponding color reduced algorithm to neighboring pixels using
14093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  serpentine-scan Floyd-Steinberg error diffusion. DitherImage returns
14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  MagickTrue if the image is dithered otherwise MagickFalse.
14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DitherImage method is:
14133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14148a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%      MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info,
14158a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%        ExceptionInfo *exception)
14163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
14183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
14203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
14223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14238a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%    o exception: return any errors or warnings in this structure.
14248a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%
14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14272392b4b33feea08c847a01411346fdce2bd6278cCristystatic DoublePixelInfo **DestroyPixelThreadSet(DoublePixelInfo **pixels)
1428e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy{
1429e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  register ssize_t
1430e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    i;
1431e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
14322392b4b33feea08c847a01411346fdce2bd6278cCristy  assert(pixels != (DoublePixelInfo **) NULL);
1433ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
14342392b4b33feea08c847a01411346fdce2bd6278cCristy    if (pixels[i] != (DoublePixelInfo *) NULL)
14352392b4b33feea08c847a01411346fdce2bd6278cCristy      pixels[i]=(DoublePixelInfo *) RelinquishMagickMemory(pixels[i]);
14362392b4b33feea08c847a01411346fdce2bd6278cCristy  pixels=(DoublePixelInfo **) RelinquishMagickMemory(pixels);
1437e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  return(pixels);
1438e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy}
1439e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
14402392b4b33feea08c847a01411346fdce2bd6278cCristystatic DoublePixelInfo **AcquirePixelThreadSet(const size_t count)
1441e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy{
14422392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
1443e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    **pixels;
1444e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1445e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  register ssize_t
1446e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    i;
1447e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1448e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  size_t
1449e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    number_threads;
1450e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
14519357bdd9a30c3d65ef8812e45220f7552dc4376bcristy  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
14522392b4b33feea08c847a01411346fdce2bd6278cCristy  pixels=(DoublePixelInfo **) AcquireQuantumMemory(number_threads,
1453e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    sizeof(*pixels));
14542392b4b33feea08c847a01411346fdce2bd6278cCristy  if (pixels == (DoublePixelInfo **) NULL)
14552392b4b33feea08c847a01411346fdce2bd6278cCristy    return((DoublePixelInfo **) NULL);
1456e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
1457e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  for (i=0; i < (ssize_t) number_threads; i++)
1458e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  {
14592392b4b33feea08c847a01411346fdce2bd6278cCristy    pixels[i]=(DoublePixelInfo *) AcquireQuantumMemory(count,2*
14602392b4b33feea08c847a01411346fdce2bd6278cCristy      sizeof(**pixels));
14612392b4b33feea08c847a01411346fdce2bd6278cCristy    if (pixels[i] == (DoublePixelInfo *) NULL)
1462e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      return(DestroyPixelThreadSet(pixels));
1463e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  }
1464e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  return(pixels);
1465e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy}
1466e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1467ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristystatic inline ssize_t CacheOffset(CubeInfo *cube_info,
14682392b4b33feea08c847a01411346fdce2bd6278cCristy  const DoublePixelInfo *pixel)
1469ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy{
1470ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy#define RedShift(pixel) (((pixel) >> CacheShift) << (0*(8-CacheShift)))
1471ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy#define GreenShift(pixel) (((pixel) >> CacheShift) << (1*(8-CacheShift)))
1472ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy#define BlueShift(pixel) (((pixel) >> CacheShift) << (2*(8-CacheShift)))
1473ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy#define AlphaShift(pixel) (((pixel) >> CacheShift) << (3*(8-CacheShift)))
1474ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy
1475ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy  ssize_t
1476ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy    offset;
1477ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy
14786f7e04238c57b6c78a9b4bda89da594775947667cristy  offset=(ssize_t) (RedShift(ScaleQuantumToChar(ClampPixel(pixel->red))) |
14796f7e04238c57b6c78a9b4bda89da594775947667cristy    GreenShift(ScaleQuantumToChar(ClampPixel(pixel->green))) |
14806f7e04238c57b6c78a9b4bda89da594775947667cristy    BlueShift(ScaleQuantumToChar(ClampPixel(pixel->blue))));
1481ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy  if (cube_info->associate_alpha != MagickFalse)
14826f7e04238c57b6c78a9b4bda89da594775947667cristy    offset|=AlphaShift(ScaleQuantumToChar(ClampPixel(pixel->alpha)));
1483ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy  return(offset);
1484ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy}
1485ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy
14868a11cb146177680bfc1b7d89a8cd0c8f2befe468cristystatic MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info,
14878a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  ExceptionInfo *exception)
14883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define DitherImageTag  "Dither/Image"
14903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1491c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
1492c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
1493c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
14942392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
14952392b4b33feea08c847a01411346fdce2bd6278cCristy    **pixels;
14962392b4b33feea08c847a01411346fdce2bd6278cCristy
14973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1498e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    status;
14993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1500847620f4bd8fefe706e29da8299ffb6f60124915cristy  ssize_t
1501847620f4bd8fefe706e29da8299ffb6f60124915cristy    y;
1502847620f4bd8fefe706e29da8299ffb6f60124915cristy
15033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
15043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Distribute quantization error using Floyd-Steinberg.
15053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1506e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  pixels=AcquirePixelThreadSet(image->columns);
15072392b4b33feea08c847a01411346fdce2bd6278cCristy  if (pixels == (DoublePixelInfo **) NULL)
15083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
1509e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  status=MagickTrue;
151046ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
1511bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
15123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
1513e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    const int
1514e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      id = GetOpenMPThreadId();
1515e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1516e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    CubeInfo
1517e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      cube;
1518e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
15192392b4b33feea08c847a01411346fdce2bd6278cCristy    DoublePixelInfo
1520e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      *current,
1521e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      *previous;
1522e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
15234c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
152405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
1525ecc31b159fd21093c91198f7fa26072d288e5230cristy
1526bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register ssize_t
15273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x;
15283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1529e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    size_t
1530e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      index;
1531e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1532e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    ssize_t
1533e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      v;
1534e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1535e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    if (status == MagickFalse)
1536e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      continue;
15373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1538acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
1539e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      {
1540e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        status=MagickFalse;
154100cbdd6ff8b85d29b7e9a3fc3dba23bbf9138aebcristy        continue;
1542e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      }
1543e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    cube=(*cube_info);
1544e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    current=pixels[id]+(y & 0x01)*image->columns;
1545e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy    previous=pixels[id]+((y+1) & 0x01)*image->columns;
15464c08aed51c5899665ade97263692328eea4af106cristy    v=(ssize_t) ((y & 0x01) != 0 ? -1 : 1);
1547bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
15483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
15492392b4b33feea08c847a01411346fdce2bd6278cCristy      DoublePixelInfo
1550e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        color,
1551e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        pixel;
1552e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1553e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      register ssize_t
1554e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        i;
1555e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1556e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      ssize_t
1557e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        u;
1558e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
15594c08aed51c5899665ade97263692328eea4af106cristy      u=(y & 0x01) != 0 ? (ssize_t) image->columns-1-x : x;
156099372baeb53919561e3d3c69a61f6284f794da52cristy      AssociateAlphaPixel(image,&cube,q+u*GetPixelChannels(image),&pixel);
15613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (x > 0)
15623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
15633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.red+=7*current[u-v].red/16;
15643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.green+=7*current[u-v].green/16;
15653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.blue+=7*current[u-v].blue/16;
1566e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          if (cube.associate_alpha != MagickFalse)
15674c08aed51c5899665ade97263692328eea4af106cristy            pixel.alpha+=7*current[u-v].alpha/16;
15683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
15693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (y > 0)
15703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1571bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          if (x < (ssize_t) (image->columns-1))
15723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
15733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.red+=previous[u+v].red/16;
15743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.green+=previous[u+v].green/16;
15753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.blue+=previous[u+v].blue/16;
1576e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy              if (cube.associate_alpha != MagickFalse)
15774c08aed51c5899665ade97263692328eea4af106cristy                pixel.alpha+=previous[u+v].alpha/16;
15783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
15793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.red+=5*previous[u].red/16;
15803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.green+=5*previous[u].green/16;
15813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel.blue+=5*previous[u].blue/16;
1582e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          if (cube.associate_alpha != MagickFalse)
15834c08aed51c5899665ade97263692328eea4af106cristy            pixel.alpha+=5*previous[u].alpha/16;
15843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (x > 0)
15853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
15863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.red+=3*previous[u-v].red/16;
15873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.green+=3*previous[u-v].green/16;
15883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel.blue+=3*previous[u-v].blue/16;
1589e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy              if (cube.associate_alpha != MagickFalse)
15904c08aed51c5899665ade97263692328eea4af106cristy                pixel.alpha+=3*previous[u-v].alpha/16;
15913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
15923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
15936f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.red=(double) ClampPixel(pixel.red);
15946f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.green=(double) ClampPixel(pixel.green);
15956f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.blue=(double) ClampPixel(pixel.blue);
1596e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      if (cube.associate_alpha != MagickFalse)
15976f7e04238c57b6c78a9b4bda89da594775947667cristy        pixel.alpha=(double) ClampPixel(pixel.alpha);
1598e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      i=CacheOffset(&cube,&pixel);
1599e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      if (cube.cache[i] < 0)
16003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
16013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          register NodeInfo
16023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *node_info;
16033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1604bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          register size_t
1605aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk            node_id;
16063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
16083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Identify the deepest node containing the pixel's color.
16093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
1610e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          node_info=cube.root;
1611bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
16123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
1613aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk            node_id=ColorToNodeId(&cube,&pixel,index);
1614aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk            if (node_info->child[node_id] == (NodeInfo *) NULL)
16153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
1616aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk            node_info=node_info->child[node_id];
16173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
16183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
16193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Find closest color among siblings and their children.
16203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
1621e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          cube.target=pixel;
16227bdaee5e9570d0aa9dc0992f58a787f3ca10927acristy          cube.distance=(double) (4.0*(QuantumRange+1.0)*(QuantumRange+1.0)+
16237bdaee5e9570d0aa9dc0992f58a787f3ca10927acristy            1.0);
1624e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          ClosestColor(image,&cube,node_info->parent);
1625e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          cube.cache[i]=(ssize_t) cube.color_number;
16263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
16273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
16283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Assign pixel to closest colormap entry.
16293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
1630e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      index=(size_t) cube.cache[i];
16313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->storage_class == PseudoClass)
163299372baeb53919561e3d3c69a61f6284f794da52cristy        SetPixelIndex(image,(Quantum) index,q+u*GetPixelChannels(image));
1633e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      if (cube.quantize_info->measure_error == MagickFalse)
16343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
163599372baeb53919561e3d3c69a61f6284f794da52cristy          SetPixelRed(image,ClampToQuantum(image->colormap[index].red),
163699372baeb53919561e3d3c69a61f6284f794da52cristy            q+u*GetPixelChannels(image));
163799372baeb53919561e3d3c69a61f6284f794da52cristy          SetPixelGreen(image,ClampToQuantum(image->colormap[index].green),
163899372baeb53919561e3d3c69a61f6284f794da52cristy            q+u*GetPixelChannels(image));
163999372baeb53919561e3d3c69a61f6284f794da52cristy          SetPixelBlue(image,ClampToQuantum(image->colormap[index].blue),
164099372baeb53919561e3d3c69a61f6284f794da52cristy            q+u*GetPixelChannels(image));
1641e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          if (cube.associate_alpha != MagickFalse)
164299372baeb53919561e3d3c69a61f6284f794da52cristy            SetPixelAlpha(image,ClampToQuantum(image->colormap[index].alpha),
164399372baeb53919561e3d3c69a61f6284f794da52cristy              q+u*GetPixelChannels(image));
16443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
16453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1646e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        status=MagickFalse;
16473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
16483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Store the error.
16493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
1650b0de93fdedaac769cb08e15b3ec176d4c9078907cristy      AssociateAlphaPixelInfo(&cube,image->colormap+index,&color);
16513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      current[u].red=pixel.red-color.red;
16523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      current[u].green=pixel.green-color.green;
16533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      current[u].blue=pixel.blue-color.blue;
1654e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      if (cube.associate_alpha != MagickFalse)
16554c08aed51c5899665ade97263692328eea4af106cristy        current[u].alpha=pixel.alpha-color.alpha;
1656e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy      if (image->progress_monitor != (MagickProgressMonitor) NULL)
1657e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        {
1658e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          MagickBooleanType
1659e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            proceed;
1660e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy
1661e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          proceed=SetImageProgress(image,DitherImageTag,(MagickOffsetType) y,
1662e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            image->rows);
1663e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy          if (proceed == MagickFalse)
1664e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy            status=MagickFalse;
1665e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy        }
16663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
16673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
1669e9717acf3194d31973b9fcf0d2709cc277da5ecdcristy  pixels=DestroyPixelThreadSet(pixels);
16703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
16713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
16723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16733ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
16748a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  RiemersmaDither(Image *,CacheView *,CubeInfo *,const unsigned int,
167509e81245d1499e747d676f1004992619e8d8d664cristy    ExceptionInfo *);
16763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16773ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void Riemersma(Image *image,CacheView *image_view,CubeInfo *cube_info,
16788a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  const size_t level,const unsigned int direction,ExceptionInfo *exception)
16793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
16803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (level == 1)
16813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch (direction)
16823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
16833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case WestGravity:
16843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
16858a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
16868a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
16878a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
16888a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
16898a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
16908a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
16913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
16923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
16933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EastGravity:
16943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
16958a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
16968a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
16978a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
16988a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
16998a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
17008a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case NorthGravity:
17043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17058a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
17068a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17078a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
17088a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17098a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
17108a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case SouthGravity:
17143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17158a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
17168a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17178a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
17188a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17198a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
17208a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
17243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
17263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
17273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch (direction)
17283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
17293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case WestGravity:
17303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17318a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
17328a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17338a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
17348a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17358a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,WestGravity,
17368a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17378a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
17388a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17398a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,WestGravity,
17408a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17418a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
17428a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17438a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
17448a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EastGravity:
17483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17498a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
17508a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17518a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
17528a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17538a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,EastGravity,
17548a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17558a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
17568a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17578a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,EastGravity,
17588a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17598a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
17608a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17618a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
17628a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case NorthGravity:
17663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17678a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,WestGravity,
17688a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17698a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
17708a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17718a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
17728a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17738a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
17748a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17758a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
17768a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17778a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
17788a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17798a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,EastGravity,
17808a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
17823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
17833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case SouthGravity:
17843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
17858a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,EastGravity,
17868a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17878a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
17888a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17898a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
17908a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17918a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
17928a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17938a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
17948a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17958a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
17968a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17978a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy        Riemersma(image,image_view,cube_info,level-1,WestGravity,
17988a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy          exception);
17993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
18003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
18013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
18023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
18033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
18043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
18053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18063ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
18078a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  CubeInfo *cube_info,const unsigned int direction,ExceptionInfo *exception)
18083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
18093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define DitherImageTag  "Dither/Image"
18103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18112392b4b33feea08c847a01411346fdce2bd6278cCristy  DoublePixelInfo
18123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    color,
18133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel;
18143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18152392b4b33feea08c847a01411346fdce2bd6278cCristy  MagickBooleanType
18162392b4b33feea08c847a01411346fdce2bd6278cCristy    proceed;
18172392b4b33feea08c847a01411346fdce2bd6278cCristy
18183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register CubeInfo
18193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
18203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1821bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
18223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    index;
18233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=cube_info;
1825bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if ((p->x >= 0) && (p->x < (ssize_t) image->columns) &&
1826bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      (p->y >= 0) && (p->y < (ssize_t) image->rows))
18273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
18284c08aed51c5899665ade97263692328eea4af106cristy      register Quantum
182905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk        *magick_restrict q;
18303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1831ecc31b159fd21093c91198f7fa26072d288e5230cristy      register ssize_t
1832ecc31b159fd21093c91198f7fa26072d288e5230cristy        i;
1833ecc31b159fd21093c91198f7fa26072d288e5230cristy
18343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
18353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Distribute error.
18363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
18373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
1838acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy      if (q == (Quantum *) NULL)
18393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return(MagickFalse);
18404c08aed51c5899665ade97263692328eea4af106cristy      AssociateAlphaPixel(image,cube_info,q,&pixel);
18413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < ErrorQueueLength; i++)
18423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
18433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel.red+=p->weights[i]*p->error[i].red;
18443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel.green+=p->weights[i]*p->error[i].green;
18453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel.blue+=p->weights[i]*p->error[i].blue;
18463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (cube_info->associate_alpha != MagickFalse)
18474c08aed51c5899665ade97263692328eea4af106cristy          pixel.alpha+=p->weights[i]*p->error[i].alpha;
18483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
18496f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.red=(double) ClampPixel(pixel.red);
18506f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.green=(double) ClampPixel(pixel.green);
18516f7e04238c57b6c78a9b4bda89da594775947667cristy      pixel.blue=(double) ClampPixel(pixel.blue);
18523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->associate_alpha != MagickFalse)
18536f7e04238c57b6c78a9b4bda89da594775947667cristy        pixel.alpha=(double) ClampPixel(pixel.alpha);
1854ca972dea9b8c15a9ef07ad0d0e61ac05284b921bcristy      i=CacheOffset(cube_info,&pixel);
18553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p->cache[i] < 0)
18563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
18573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          register NodeInfo
18583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *node_info;
18593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1860bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          register size_t
18613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            id;
18623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
18643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Identify the deepest node containing the pixel's color.
18653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
18663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          node_info=p->root;
1867bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
18683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
18693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            id=ColorToNodeId(cube_info,&pixel,index);
18703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (node_info->child[id] == (NodeInfo *) NULL)
18713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
18723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            node_info=node_info->child[id];
18733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
18743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
18753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Find closest color among siblings and their children.
18763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
18773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          p->target=pixel;
1878a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          p->distance=(double) (4.0*(QuantumRange+1.0)*((double)
18793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            QuantumRange+1.0)+1.0);
18803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          ClosestColor(image,p,node_info->parent);
1881bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          p->cache[i]=(ssize_t) p->color_number;
18823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
18833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
18843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Assign pixel to closest colormap entry.
18853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
18864c08aed51c5899665ade97263692328eea4af106cristy      index=(size_t) p->cache[i];
18873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->storage_class == PseudoClass)
18884c08aed51c5899665ade97263692328eea4af106cristy        SetPixelIndex(image,(Quantum) index,q);
18893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->quantize_info->measure_error == MagickFalse)
18903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1891e42f658533644aecb733785ffd91b286d6778deacristy          SetPixelRed(image,ClampToQuantum(image->colormap[index].red),q);
1892e42f658533644aecb733785ffd91b286d6778deacristy          SetPixelGreen(image,ClampToQuantum(image->colormap[index].green),q);
1893e42f658533644aecb733785ffd91b286d6778deacristy          SetPixelBlue(image,ClampToQuantum(image->colormap[index].blue),q);
18943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (cube_info->associate_alpha != MagickFalse)
1895e42f658533644aecb733785ffd91b286d6778deacristy            SetPixelAlpha(image,ClampToQuantum(image->colormap[index].alpha),q);
18963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
18973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
18983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return(MagickFalse);
18993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
19003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Propagate the error as the last entry of the error queue.
19013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
19023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) CopyMagickMemory(p->error,p->error+1,(ErrorQueueLength-1)*
19033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        sizeof(p->error[0]));
1904b0de93fdedaac769cb08e15b3ec176d4c9078907cristy      AssociateAlphaPixelInfo(cube_info,image->colormap+index,&color);
19053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p->error[ErrorQueueLength-1].red=pixel.red-color.red;
19063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p->error[ErrorQueueLength-1].green=pixel.green-color.green;
19073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p->error[ErrorQueueLength-1].blue=pixel.blue-color.blue;
19083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (cube_info->associate_alpha != MagickFalse)
19094c08aed51c5899665ade97263692328eea4af106cristy        p->error[ErrorQueueLength-1].alpha=pixel.alpha-color.alpha;
19103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
19113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (proceed == MagickFalse)
19123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return(MagickFalse);
19133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p->offset++;
19143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (direction)
19163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
19173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case WestGravity: p->x--; break;
19183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case EastGravity: p->x++; break;
19193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case NorthGravity: p->y--; break;
19203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case SouthGravity: p->y++; break;
19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19258a11cb146177680bfc1b7d89a8cd0c8f2befe468cristystatic MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info,
19268a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  ExceptionInfo *exception)
19273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1928c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
1929c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
1930c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
19313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
19323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
19333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1934bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
19353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
19363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1937bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
19383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    depth;
19393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1940fb7e9cd79d6dac608ba2ca80a3a2870056bfc851cristy  if (cube_info->quantize_info->dither_method != RiemersmaDitherMethod)
19418a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy    return(FloydSteinbergDither(image,cube_info,exception));
19423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
1943cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy    Distribute quantization error along a Hilbert curve.
19443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(cube_info->error,0,ErrorQueueLength*
19463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*cube_info->error));
19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->x=0;
19483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->y=0;
1949bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  i=MagickMax((ssize_t) image->columns,(ssize_t) image->rows);
19503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (depth=1; i != 0; depth++)
19513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i>>=1;
1952bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if ((ssize_t) (1L << depth) < MagickMax((ssize_t) image->columns,(ssize_t) image->rows))
19533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    depth++;
19543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->offset=0;
19553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->span=(MagickSizeType) image->columns*image->rows;
195646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
19573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (depth > 1)
19588a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy    Riemersma(image,image_view,cube_info,depth-1,NorthGravity,exception);
19598a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  status=RiemersmaDither(image,image_view,cube_info,ForgetGravity,exception);
19603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
19613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
19623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
19653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   G e t C u b e I n f o                                                     %
19703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetCubeInfo() initialize the Cube data structure.
19763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetCubeInfo method is:
19783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      CubeInfo GetCubeInfo(const QuantizeInfo *quantize_info,
1980bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        const size_t depth,const size_t maximum_colors)
19813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
19833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
19853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o depth: Normally, this integer value is zero or one.  A zero or
19873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      one tells Quantize to choose a optimal tree depth of Log4(number_colors).
19883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      A tree of this depth generally allows the best representation of the
19893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      reference image with the least amount of memory and the fastest
19903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      computational speed.  In some cases, such as an image with low color
19913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      dispersion (a few number of colors), a value other than
19923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Log4(number_colors) is required.  To expand the color tree completely,
19933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      use a value of 8.
19943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o maximum_colors: maximum colors.
19963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
19983ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic CubeInfo *GetCubeInfo(const QuantizeInfo *quantize_info,
1999bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  const size_t depth,const size_t maximum_colors)
20003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
20013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CubeInfo
20023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cube_info;
20033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2004a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
20053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sum,
20063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    weight;
20073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2008bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
20093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
20103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2011ecc31b159fd21093c91198f7fa26072d288e5230cristy  size_t
2012ecc31b159fd21093c91198f7fa26072d288e5230cristy    length;
2013ecc31b159fd21093c91198f7fa26072d288e5230cristy
20143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
20153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize tree to describe color cube_info.
20163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
201773bd4a51b419e914565bdf204bf1540dc4c8ee26cristy  cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
20183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info == (CubeInfo *) NULL)
20193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return((CubeInfo *) NULL);
20203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
20213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->depth=depth;
20223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info->depth > MaxTreeDepth)
20233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->depth=MaxTreeDepth;
20243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info->depth < 2)
20253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->depth=2;
20263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->maximum_colors=maximum_colors;
20273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
20283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize root node.
20293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
20303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->root=GetNodeInfo(cube_info,0,0,(NodeInfo *) NULL);
20313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info->root == (NodeInfo *) NULL)
20323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return((CubeInfo *) NULL);
20333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->root->parent=cube_info->root;
20343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->quantize_info=CloneQuantizeInfo(quantize_info);
2035cbda611068350bf4459f2dda1951f8823702e129cristy  if (cube_info->quantize_info->dither_method == NoDitherMethod)
20363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(cube_info);
20373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
20383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize dither resources.
20393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
20403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=(size_t) (1UL << (4*(8-CacheShift)));
2041a321eb7fb3b35eed694d0366543450d023900b5bcristy  cube_info->memory_info=AcquireVirtualMemory(length,sizeof(*cube_info->cache));
2042a321eb7fb3b35eed694d0366543450d023900b5bcristy  if (cube_info->memory_info == (MemoryInfo *) NULL)
20433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return((CubeInfo *) NULL);
2044a321eb7fb3b35eed694d0366543450d023900b5bcristy  cube_info->cache=(ssize_t *) GetVirtualMemoryBlob(cube_info->memory_info);
20453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
20463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize color cache.
20473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
2048d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk  (void) ResetMagickMemory(cube_info->cache,(-1),sizeof(*cube_info->cache)*
2049d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk    length);
20503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2051cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy    Distribute weights along a curve of exponential decay.
20523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
20533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  weight=1.0;
20543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; i < ErrorQueueLength; i++)
20553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
20563e3ec3afbb0782697f201cbe30a56794c10dc7efcristy    cube_info->weights[ErrorQueueLength-i-1]=PerceptibleReciprocal(weight);
20573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    weight*=exp(log(((double) QuantumRange+1.0))/(ErrorQueueLength-1.0));
20583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
20593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
20603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Normalize the weighting factors.
20613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
20623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  weight=0.0;
20633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; i < ErrorQueueLength; i++)
20643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    weight+=cube_info->weights[i];
20653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  sum=0.0;
20663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; i < ErrorQueueLength; i++)
20673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
20683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->weights[i]/=weight;
20693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sum+=cube_info->weights[i];
20703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
20713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->weights[0]+=1.0-sum;
20723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(cube_info);
20733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
20743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
20763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   G e t N o d e I n f o                                                     %
20813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetNodeInfo() allocates memory for a new node in the color cube tree and
20873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  presets all fields to zero.
20883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetNodeInfo method is:
20903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2091bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t id,
2092bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        const size_t level,NodeInfo *parent)
20933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
20953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node: The GetNodeInfo method returns a pointer to a queue of nodes.
20973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o id: Specifies the child number of the node.
20993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o level: Specifies the level in the storage_class the node resides.
21013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2103bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t id,
2104bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  const size_t level,NodeInfo *parent)
21053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
21063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
21073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *node_info;
21083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
21093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info->free_nodes == 0)
21103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
21113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Nodes
21123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *nodes;
21133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
21143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
21153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Allocate a new queue of nodes.
21163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
211773bd4a51b419e914565bdf204bf1540dc4c8ee26cristy      nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
21183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (nodes == (Nodes *) NULL)
21193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return((NodeInfo *) NULL);
21203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      nodes->nodes=(NodeInfo *) AcquireQuantumMemory(NodesInAList,
21213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        sizeof(*nodes->nodes));
21223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (nodes->nodes == (NodeInfo *) NULL)
21233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return((NodeInfo *) NULL);
21243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      nodes->next=cube_info->node_queue;
21253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->node_queue=nodes;
21263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->next_node=nodes->nodes;
21273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->free_nodes=NodesInAList;
21283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
21293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->nodes++;
21303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->free_nodes--;
21313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  node_info=cube_info->next_node++;
21323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
21333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  node_info->parent=parent;
21343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  node_info->id=id;
21353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  node_info->level=level;
21363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(node_info);
21373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
21383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
21393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
21403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  G e t I m a g e Q u a n t i z e E r r o r                                  %
21453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetImageQuantizeError() measures the difference between the original
21513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  and quantized images.  This difference is the total quantization error.
21523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The error is computed by summing over all pixels in an image the distance
21533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  squared in RGB space between each reference pixel value and its quantized
21543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  value.  These values are computed:
21553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o mean_error_per_pixel:  This value is the mean error for any single
21573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      pixel in the image.
21583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o normalized_mean_square_error:  This value is the normalized mean
21603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      quantization error for any single pixel in the image.  This distance
21613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      measure is normalized to a range between 0 and 1.  It is independent
21623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      of the range of red, green, and blue values in the image.
21633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o normalized_maximum_square_error:  Thsi value is the normalized
21653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      maximum quantization error for any single pixel in the image.  This
21663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      distance measure is normalized to a range between 0 and 1.  It is
21673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      independent of the range of red, green, and blue values in your image.
21683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetImageQuantizeError method is:
21703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21718a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%      MagickBooleanType GetImageQuantizeError(Image *image,
21728a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%        ExceptionInfo *exception)
21733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
21753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
21773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21788a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%    o exception: return any errors or warnings in this structure.
21798a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy%
21803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
21818a11cb146177680bfc1b7d89a8cd0c8f2befe468cristyMagickExport MagickBooleanType GetImageQuantizeError(Image *image,
21828a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  ExceptionInfo *exception)
21833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2184c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
2185c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
2186c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
2187a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  double
21883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha,
21893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    area,
21903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    beta,
21913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    distance,
21923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_error,
21933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    mean_error,
21943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    mean_error_per_pixel;
21953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2196bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
21973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    index;
21983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2199ecc31b159fd21093c91198f7fa26072d288e5230cristy  ssize_t
2200ecc31b159fd21093c91198f7fa26072d288e5230cristy    y;
2201ecc31b159fd21093c91198f7fa26072d288e5230cristy
22023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2203e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
22043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
22053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
22068a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  image->total_colors=GetNumberColors(image,(FILE *) NULL,exception);
22073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(&image->error,0,sizeof(image->error));
22083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->storage_class == DirectClass)
22093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
22103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=1.0;
22113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  beta=1.0;
22123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  area=3.0*image->columns*image->rows;
22133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  maximum_error=0.0;
22143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  mean_error_per_pixel=0.0;
22153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  mean_error=0.0;
221646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireVirtualCacheView(image,exception);
2217bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
22183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
22194c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
222005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
22213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2222bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register ssize_t
22233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x;
22243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
22264c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
22273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2228bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
22293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
223009e81245d1499e747d676f1004992619e8d8d664cristy      index=GetPixelIndex(image,p);
223109e81245d1499e747d676f1004992619e8d8d664cristy      if (image->alpha_trait == BlendPixelTrait)
22323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
2233a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
2234a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          beta=(double) (QuantumScale*image->colormap[index].alpha);
22353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
22363bdd925dbb0804df99e548c50667670319655816cristy      distance=fabs((double) (alpha*GetPixelRed(image,p)-beta*
22373bdd925dbb0804df99e548c50667670319655816cristy        image->colormap[index].red));
22383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error_per_pixel+=distance;
22393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error+=distance*distance;
22403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (distance > maximum_error)
22413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        maximum_error=distance;
22423bdd925dbb0804df99e548c50667670319655816cristy      distance=fabs((double) (alpha*GetPixelGreen(image,p)-beta*
22433bdd925dbb0804df99e548c50667670319655816cristy        image->colormap[index].green));
22443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error_per_pixel+=distance;
22453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error+=distance*distance;
22463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (distance > maximum_error)
22473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        maximum_error=distance;
22483bdd925dbb0804df99e548c50667670319655816cristy      distance=fabs((double) (alpha*GetPixelBlue(image,p)-beta*
22493bdd925dbb0804df99e548c50667670319655816cristy        image->colormap[index].blue));
22503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error_per_pixel+=distance;
22513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      mean_error+=distance*distance;
22523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (distance > maximum_error)
22533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        maximum_error=distance;
2254ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(image);
22553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
22563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
22573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
22583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->error.mean_error_per_pixel=(double) mean_error_per_pixel/area;
22593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->error.normalized_mean_error=(double) QuantumScale*QuantumScale*
22603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    mean_error/area;
22613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->error.normalized_maximum_error=(double) QuantumScale*maximum_error;
22623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
22633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
22643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
22663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
22673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   G e t Q u a n t i z e I n f o                                             %
22713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
22743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
22753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetQuantizeInfo() initializes the QuantizeInfo structure.
22773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetQuantizeInfo method is:
22793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      GetQuantizeInfo(QuantizeInfo *quantize_info)
22813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
22833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to a QuantizeInfo structure.
22853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
22873ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
22883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
22893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
22903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(quantize_info != (QuantizeInfo *) NULL);
22913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(quantize_info,0,sizeof(*quantize_info));
22923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info->number_colors=256;
22933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info->dither_method=RiemersmaDitherMethod;
22943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info->colorspace=UndefinedColorspace;
22953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info->measure_error=MagickFalse;
2296e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  quantize_info->signature=MagickCoreSignature;
22973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
22983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
23013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
23023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
23033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2304018f07f7333b25743d0afff892450cebdb905c1acristy%     P o s t e r i z e I m a g e                                             %
23053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
23063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
23073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
23083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
23093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
23103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  PosterizeImage() reduces the image to a limited number of colors for a
23113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  "poster" effect.
23123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
23133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the PosterizeImage method is:
23143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2315bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      MagickBooleanType PosterizeImage(Image *image,const size_t levels,
2316cbda611068350bf4459f2dda1951f8823702e129cristy%        const DitherMethod dither_method,ExceptionInfo *exception)
23173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
23183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
23193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
23203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: Specifies a pointer to an Image structure.
23213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
23223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o levels: Number of color levels allowed in each channel.  Very low values
23233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      (2, 3, or 4) have the most visible effect.
23243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2325cbda611068350bf4459f2dda1951f8823702e129cristy%    o dither_method: choose from UndefinedDitherMethod, NoDitherMethod,
2326cbda611068350bf4459f2dda1951f8823702e129cristy%      RiemersmaDitherMethod, FloydSteinbergDitherMethod.
23273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2328018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
2329018f07f7333b25743d0afff892450cebdb905c1acristy%
23303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2331d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
233272844f182b47d17dc2b4e9f1062ba434e5852fd6cristystatic inline double MagickRound(double x)
23334d727156230459f39669d580f55fae20e1b303f3cristy{
23344d727156230459f39669d580f55fae20e1b303f3cristy  /*
2335ecc31b159fd21093c91198f7fa26072d288e5230cristy    Round the fraction to nearest integer.
23364d727156230459f39669d580f55fae20e1b303f3cristy  */
2337ae0a3fcb5e88aba2468892d7710c322885d80fcdcristy  if ((x-floor(x)) < (ceil(x)-x))
233872844f182b47d17dc2b4e9f1062ba434e5852fd6cristy    return(floor(x));
233972844f182b47d17dc2b4e9f1062ba434e5852fd6cristy  return(ceil(x));
23404d727156230459f39669d580f55fae20e1b303f3cristy}
23414d727156230459f39669d580f55fae20e1b303f3cristy
2342d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristyMagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
2343cbda611068350bf4459f2dda1951f8823702e129cristy  const DitherMethod dither_method,ExceptionInfo *exception)
2344d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy{
2345d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#define PosterizeImageTag  "Posterize/Image"
23464d727156230459f39669d580f55fae20e1b303f3cristy#define PosterizePixel(pixel) (Quantum) (QuantumRange*(MagickRound( \
23473e9cad0e993ec8b035b5a19f95afc351da466098cristy  QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))
2348d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
2349c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
2350d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    *image_view;
2351c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
23523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
23533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
23543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2355d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  MagickOffsetType
2356d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    progress;
2357d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
23583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantizeInfo
23593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantize_info;
23603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2361847620f4bd8fefe706e29da8299ffb6f60124915cristy  register ssize_t
2362847620f4bd8fefe706e29da8299ffb6f60124915cristy    i;
2363847620f4bd8fefe706e29da8299ffb6f60124915cristy
2364847620f4bd8fefe706e29da8299ffb6f60124915cristy  ssize_t
2365d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    y;
2366847620f4bd8fefe706e29da8299ffb6f60124915cristy
23673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2368e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
23693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
23703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
237109e81245d1499e747d676f1004992619e8d8d664cristy  assert(exception != (ExceptionInfo *) NULL);
2372e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
2373d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  if (image->storage_class == PseudoClass)
2374d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
2375ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy    #pragma omp parallel for schedule(static,4) shared(progress,status) \
2376cb7dfccc2e3a9d57a44294cde5228e6f3f27d003cristy      magick_threads(image,image,1,1)
2377d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#endif
2378d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    for (i=0; i < (ssize_t) image->colors; i++)
23793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2380d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      /*
2381d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        Posterize colormap.
2382d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      */
2383ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2384e42f658533644aecb733785ffd91b286d6778deacristy        image->colormap[i].red=(double)
2385e42f658533644aecb733785ffd91b286d6778deacristy          PosterizePixel(image->colormap[i].red);
2386ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2387e42f658533644aecb733785ffd91b286d6778deacristy        image->colormap[i].green=(double)
2388e42f658533644aecb733785ffd91b286d6778deacristy          PosterizePixel(image->colormap[i].green);
2389ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2390e42f658533644aecb733785ffd91b286d6778deacristy        image->colormap[i].blue=(double)
2391e42f658533644aecb733785ffd91b286d6778deacristy          PosterizePixel(image->colormap[i].blue);
2392ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
2393e42f658533644aecb733785ffd91b286d6778deacristy        image->colormap[i].alpha=(double)
2394e42f658533644aecb733785ffd91b286d6778deacristy          PosterizePixel(image->colormap[i].alpha);
23953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
2396d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  /*
2397d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    Posterize image.
2398d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  */
2399d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  status=MagickTrue;
2400d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  progress=0;
240146ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
2402d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
2403ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
24045e6b259130f9dbe0da4666f734937017babe573acristy    magick_threads(image,image,image->rows,1)
2405d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#endif
2406d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  for (y=0; y < (ssize_t) image->rows; y++)
2407d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  {
24084c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
240905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
2410d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
2411d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    register ssize_t
2412d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      x;
2413d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
2414d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    if (status == MagickFalse)
2415d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      continue;
2416d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2417acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
24183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
2419d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        status=MagickFalse;
2420d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        continue;
24213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
2422d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    for (x=0; x < (ssize_t) image->columns; x++)
24233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2424ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
24254c08aed51c5899665ade97263692328eea4af106cristy        SetPixelRed(image,PosterizePixel(GetPixelRed(image,q)),q);
2426ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
24274c08aed51c5899665ade97263692328eea4af106cristy        SetPixelGreen(image,PosterizePixel(GetPixelGreen(image,q)),q);
2428ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
24294c08aed51c5899665ade97263692328eea4af106cristy        SetPixelBlue(image,PosterizePixel(GetPixelBlue(image,q)),q);
2430ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
24314c08aed51c5899665ade97263692328eea4af106cristy          (image->colorspace == CMYKColorspace))
24324c08aed51c5899665ade97263692328eea4af106cristy        SetPixelBlack(image,PosterizePixel(GetPixelBlack(image,q)),q);
2433ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
243409e81245d1499e747d676f1004992619e8d8d664cristy          (image->alpha_trait == BlendPixelTrait))
24354c08aed51c5899665ade97263692328eea4af106cristy        SetPixelAlpha(image,PosterizePixel(GetPixelAlpha(image,q)),q);
2436ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
24373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
2438d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2439d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      status=MagickFalse;
2440d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    if (image->progress_monitor != (MagickProgressMonitor) NULL)
2441d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      {
2442d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        MagickBooleanType
2443d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy          proceed;
2444d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy
2445d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
2446130206720ba69f6ad1a981900a035e2c33714759cristy        #pragma omp critical (MagickCore_PosterizeImage)
2447d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy#endif
2448d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        proceed=SetImageProgress(image,PosterizeImageTag,progress++,
2449d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy          image->rows);
2450d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy        if (proceed == MagickFalse)
2451d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy          status=MagickFalse;
2452d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy      }
2453d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  }
2454d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  image_view=DestroyCacheView(image_view);
24553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
2456d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy  quantize_info->number_colors=(size_t) MagickMin((ssize_t) levels*levels*
2457d1a2c0fcfc2ee9b388c05b3bccfc0544a42e3a9bcristy    levels,MaxColormapSize+1);
2458cbda611068350bf4459f2dda1951f8823702e129cristy  quantize_info->dither_method=dither_method;
24593e9cad0e993ec8b035b5a19f95afc351da466098cristy  quantize_info->tree_depth=MaxTreeDepth;
2460018f07f7333b25743d0afff892450cebdb905c1acristy  status=QuantizeImage(quantize_info,image,exception);
24613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantize_info=DestroyQuantizeInfo(quantize_info);
24623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
24633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
24643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
24653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
24663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
24673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   P r u n e C h i l d                                                       %
24713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
24743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
24753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  PruneChild() deletes the given node and merges its statistics into its
24773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  parent.
24783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the PruneSubtree method is:
24803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2481f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk%      PruneChild(CubeInfo *cube_info,const NodeInfo *node_info)
24823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
24843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
24863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: pointer to node in color cube tree that is to be pruned.
24883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
24893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2490f20fa43474e61817b4b54b490ad3a425ad5ec63bdirkstatic void PruneChild(CubeInfo *cube_info,const NodeInfo *node_info)
24913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
24923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  NodeInfo
24933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *parent;
24943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2495bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
24963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
24973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2498bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
24993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
25003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
25023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
25033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
25043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2505bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
25063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
2507f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk      PruneChild(cube_info,node_info->child[i]);
25083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
25093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Merge color statistics into parent.
25103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
25113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent=node_info->parent;
25123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent->number_unique+=node_info->number_unique;
25133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent->total_color.red+=node_info->total_color.red;
25143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent->total_color.green+=node_info->total_color.green;
25153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent->total_color.blue+=node_info->total_color.blue;
25164c08aed51c5899665ade97263692328eea4af106cristy  parent->total_color.alpha+=node_info->total_color.alpha;
25173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  parent->child[node_info->id]=(NodeInfo *) NULL;
25183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->nodes--;
25193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
25203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
25223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+  P r u n e L e v e l                                                        %
25273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  PruneLevel() deletes all nodes at the bottom level of the color tree merging
25333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  their color statistics into their parent node.
25343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the PruneLevel method is:
25363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2537f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk%      PruneLevel(CubeInfo *cube_info,const NodeInfo *node_info)
25383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
25403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
25423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: pointer to node in color cube tree that is to be pruned.
25443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2546f20fa43474e61817b4b54b490ad3a425ad5ec63bdirkstatic void PruneLevel(CubeInfo *cube_info,const NodeInfo *node_info)
25473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2548bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
25493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
25503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2551bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
25523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
25533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
25553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
25563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
25573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2558bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
25593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
2560f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk      PruneLevel(cube_info,node_info->child[i]);
25613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (node_info->level == cube_info->depth)
2562f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk    PruneChild(cube_info,node_info);
25633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
25643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
25663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+  P r u n e T o C u b e D e p t h                                            %
25713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
25743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  PruneToCubeDepth() deletes any nodes at a depth greater than
25773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  cube_info->depth while merging their color statistics into their parent
25783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  node.
25793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the PruneToCubeDepth method is:
25813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2582f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk%      PruneToCubeDepth(CubeInfo *cube_info,const NodeInfo *node_info)
25833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
25853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
25873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: pointer to node in color cube tree that is to be pruned.
25893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
25903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2591f20fa43474e61817b4b54b490ad3a425ad5ec63bdirkstatic void PruneToCubeDepth(CubeInfo *cube_info,const NodeInfo *node_info)
25923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2593bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
25943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
25953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2596bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
25973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
25983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
26003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
26013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
26023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2603bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
26043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
2605f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk      PruneToCubeDepth(cube_info,node_info->child[i]);
26063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (node_info->level > cube_info->depth)
2607f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk    PruneChild(cube_info,node_info);
26083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
26093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
26113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Q u a n t i z e I m a g e                                                  %
26163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
26193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  QuantizeImage() analyzes the colors within a reference image and chooses a
26223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  fixed number of colors to represent the image.  The goal of the algorithm
26233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  is to minimize the color difference between the input and output image while
26243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  minimizing the processing time.
26253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the QuantizeImage method is:
26273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
2629018f07f7333b25743d0afff892450cebdb905c1acristy%        Image *image,ExceptionInfo *exception)
26303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
26323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
26343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
26353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
26363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2637018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
2638018f07f7333b25743d0afff892450cebdb905c1acristy%
26393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
26403ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
2641018f07f7333b25743d0afff892450cebdb905c1acristy  Image *image,ExceptionInfo *exception)
26423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
26433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CubeInfo
26443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cube_info;
26453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
26473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
26483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2649bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
26503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    depth,
26513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors;
26523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(quantize_info != (const QuantizeInfo *) NULL);
2654e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(quantize_info->signature == MagickCoreSignature);
26553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2656e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
26573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
26583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
265909e81245d1499e747d676f1004992619e8d8d664cristy  assert(exception != (ExceptionInfo *) NULL);
2660e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
26613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  maximum_colors=quantize_info->number_colors;
26623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (maximum_colors == 0)
26633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors=MaxColormapSize;
26643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (maximum_colors > MaxColormapSize)
26653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors=MaxColormapSize;
266609e81245d1499e747d676f1004992619e8d8d664cristy  if (image->alpha_trait != BlendPixelTrait)
2667400e701485153593ab9021e30df2d896d52f789ecristy    {
2668f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk      if (SetImageGray(image,exception) != MagickFalse)
2669400e701485153593ab9021e30df2d896d52f789ecristy        (void) SetGrayscaleImage(image,exception);
2670400e701485153593ab9021e30df2d896d52f789ecristy    }
26713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((image->storage_class == PseudoClass) &&
26723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (image->colors <= maximum_colors))
2673bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk    {
2674bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk      if ((quantize_info->colorspace != UndefinedColorspace) &&
2675bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk          (quantize_info->colorspace != CMYKColorspace))
2676bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk        (void) TransformImageColorspace(image,quantize_info->colorspace,
2677bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk          exception);
2678bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk      return(MagickTrue);
2679bd66cbe3ecb61270ac3a6f6298fca8e08d6ee4e9dirk    }
26803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  depth=quantize_info->tree_depth;
26813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (depth == 0)
26823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2683bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      size_t
26843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        colors;
26853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
26873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Depth of color tree is: Log4(colormap size)+2.
26883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
26893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      colors=maximum_colors;
26903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (depth=1; colors != 0; depth++)
26913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        colors>>=2;
2692cbda611068350bf4459f2dda1951f8823702e129cristy      if ((quantize_info->dither_method != NoDitherMethod) && (depth > 2))
26933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        depth--;
269409e81245d1499e747d676f1004992619e8d8d664cristy      if ((image->alpha_trait == BlendPixelTrait) && (depth > 5))
26953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        depth--;
2696f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk      if (SetImageGray(image,exception) != MagickFalse)
2697a8be0ae4b6b2c32433ef24616d06f4d50e518b3ecristy        depth=MaxTreeDepth;
26983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
26993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
27003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize color cube.
27013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
27023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
27033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info == (CubeInfo *) NULL)
27043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
27053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
27068a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  status=ClassifyImageColors(cube_info,image,exception);
27073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
27083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
27093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
2710c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk        Reduce the number of colors in the image if it contains more than the
2711c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk        maximum, otherwise we can disable dithering to improve the performance.
27123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
2713c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk      if (cube_info->colors > cube_info->maximum_colors)
2714bce0859dc2c11635c0010976b760a13e23210718dirk        ReduceImageColors(image,cube_info);
2715c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk      else
2716c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk        cube_info->quantize_info->dither_method=NoDitherMethod;
2717c772059f3d0d3241ff8afad63f63c2c953f3fa5ddirk      status=AssignImageColors(image,cube_info,exception);
27183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
27193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DestroyCubeInfo(cube_info);
27203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
27213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
27223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
27233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
27243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
27253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   Q u a n t i z e I m a g e s                                               %
27293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
27323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
27333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  QuantizeImages() analyzes the colors within a set of reference images and
27353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  chooses a fixed number of colors to represent the set.  The goal of the
27363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  algorithm is to minimize the color difference between the input and output
27373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  images while minimizing the processing time.
27383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the QuantizeImages method is:
27403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
2742018f07f7333b25743d0afff892450cebdb905c1acristy%        Image *images,ExceptionInfo *exception)
27433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
27453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
27473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
27483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o images: Specifies a pointer to a list of Image structures.
27493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2750018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
2751018f07f7333b25743d0afff892450cebdb905c1acristy%
27523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
27533ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
2754018f07f7333b25743d0afff892450cebdb905c1acristy  Image *images,ExceptionInfo *exception)
27553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
27563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CubeInfo
27573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cube_info;
27583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
27593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
27603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image;
27613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
27623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
27633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    proceed,
27643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
27653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
27663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickProgressMonitor
27673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    progress_monitor;
27683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2769bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
27703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
27713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2772bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
27733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    depth,
27743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors,
27753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_images;
27763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
27773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(quantize_info != (const QuantizeInfo *) NULL);
2778e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(quantize_info->signature == MagickCoreSignature);
27793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(images != (Image *) NULL);
2780e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(images->signature == MagickCoreSignature);
27813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (images->debug != MagickFalse)
27823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
278309e81245d1499e747d676f1004992619e8d8d664cristy  assert(exception != (ExceptionInfo *) NULL);
2784e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
27853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (GetNextImageInList(images) == (Image *) NULL)
27863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
27873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
27883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Handle a single image with QuantizeImage.
27893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
2790018f07f7333b25743d0afff892450cebdb905c1acristy      status=QuantizeImage(quantize_info,images,exception);
27913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(status);
27923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
27933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickFalse;
27943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  maximum_colors=quantize_info->number_colors;
27953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (maximum_colors == 0)
27963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors=MaxColormapSize;
27973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (maximum_colors > MaxColormapSize)
27983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    maximum_colors=MaxColormapSize;
27993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  depth=quantize_info->tree_depth;
28003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (depth == 0)
28013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2802bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      size_t
28033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        colors;
28043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
28053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
28063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Depth of color tree is: Log4(colormap size)+2.
28073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
28083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      colors=maximum_colors;
28093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (depth=1; colors != 0; depth++)
28103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        colors>>=2;
2811cbda611068350bf4459f2dda1951f8823702e129cristy      if (quantize_info->dither_method != NoDitherMethod)
28123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        depth--;
28133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
28143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
28153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize color cube.
28163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
28173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
28183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info == (CubeInfo *) NULL)
28193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
28208a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy      (void) ThrowMagickException(exception,GetMagickModule(),
2821efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
28223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
28233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
28243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_images=GetImageListLength(images);
28253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image=images;
28263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; image != (Image *) NULL; i++)
28273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
28283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
28293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->client_data);
28308a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy    status=ClassifyImageColors(cube_info,image,exception);
28313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
28323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
28333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
2834cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy    proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
2835cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy      number_images);
28363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (proceed == MagickFalse)
28373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
28383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image=GetNextImageInList(image);
28393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
28403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
28413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
28423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
28433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Reduce the number of colors in an image sequence.
28443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
28453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ReduceImageColors(images,cube_info);
28463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image=images;
28473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; image != (Image *) NULL; i++)
28483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
28493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor)
28503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          NULL,image->client_data);
2851018f07f7333b25743d0afff892450cebdb905c1acristy        status=AssignImageColors(image,cube_info,exception);
28523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
28533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
28543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) SetImageProgressMonitor(image,progress_monitor,
28553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->client_data);
2856cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy        proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
2857cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy          number_images);
28583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (proceed == MagickFalse)
28593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
28603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        image=GetNextImageInList(image);
28613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
28623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
28633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DestroyCubeInfo(cube_info);
28643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
28653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
28663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
28673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
28683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
28703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
28713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2872b2f9ca89786b493edecc00f13c436a003117c441cristy+   Q u a n t i z e E r r o r F l a t t e n                                   %
2873b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
2874b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
2875b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
2876b2f9ca89786b493edecc00f13c436a003117c441cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877b2f9ca89786b493edecc00f13c436a003117c441cristy%
2878b2f9ca89786b493edecc00f13c436a003117c441cristy%  QuantizeErrorFlatten() traverses the color cube and flattens the quantization
2879a5573bc60ffe027a36c107ce00a8c6135bed3ee1cristy%  error into a sorted 1D array.  This accelerates the color reduction process.
2880b2f9ca89786b493edecc00f13c436a003117c441cristy%
2881b2f9ca89786b493edecc00f13c436a003117c441cristy%  Contributed by Yoya.
2882b2f9ca89786b493edecc00f13c436a003117c441cristy%
288346a9a1530a17ea11ec1e9212b5184b5a71d55c4ccristy%  The format of the QuantizeErrorFlatten method is:
2884b2f9ca89786b493edecc00f13c436a003117c441cristy%
28855289eadbd4cd6158bf95bfc78836f3b088d59d9fdirk%      size_t QuantizeErrorFlatten(const CubeInfo *cube_info,
288606909863026300327af4ae61823f84976a179b9fcristy%        const NodeInfo *node_info,const ssize_t offset,
288709e81245d1499e747d676f1004992619e8d8d664cristy%        double *quantize_error)
2888b2f9ca89786b493edecc00f13c436a003117c441cristy%
2889b2f9ca89786b493edecc00f13c436a003117c441cristy%  A description of each parameter follows.
2890b2f9ca89786b493edecc00f13c436a003117c441cristy%
2891b2f9ca89786b493edecc00f13c436a003117c441cristy%    o cube_info: A pointer to the Cube structure.
2892b2f9ca89786b493edecc00f13c436a003117c441cristy%
2893b2f9ca89786b493edecc00f13c436a003117c441cristy%    o node_info: pointer to node in color cube tree that is current pointer.
2894b2f9ca89786b493edecc00f13c436a003117c441cristy%
2895b2f9ca89786b493edecc00f13c436a003117c441cristy%    o offset: quantize error offset.
2896b2f9ca89786b493edecc00f13c436a003117c441cristy%
2897b2f9ca89786b493edecc00f13c436a003117c441cristy%    o quantize_error: the quantization error vector.
2898b2f9ca89786b493edecc00f13c436a003117c441cristy%
2899b2f9ca89786b493edecc00f13c436a003117c441cristy*/
29005289eadbd4cd6158bf95bfc78836f3b088d59d9fdirkstatic size_t QuantizeErrorFlatten(const CubeInfo *cube_info,
290109e81245d1499e747d676f1004992619e8d8d664cristy  const NodeInfo *node_info,const ssize_t offset,double *quantize_error)
2902b2f9ca89786b493edecc00f13c436a003117c441cristy{
2903b2f9ca89786b493edecc00f13c436a003117c441cristy  register ssize_t
2904b2f9ca89786b493edecc00f13c436a003117c441cristy    i;
2905b2f9ca89786b493edecc00f13c436a003117c441cristy
2906b2f9ca89786b493edecc00f13c436a003117c441cristy  size_t
2907b2f9ca89786b493edecc00f13c436a003117c441cristy    n,
2908b2f9ca89786b493edecc00f13c436a003117c441cristy    number_children;
2909b2f9ca89786b493edecc00f13c436a003117c441cristy
291006909863026300327af4ae61823f84976a179b9fcristy  if (offset >= (ssize_t) cube_info->nodes)
2911b2f9ca89786b493edecc00f13c436a003117c441cristy    return(0);
2912b2f9ca89786b493edecc00f13c436a003117c441cristy  quantize_error[offset]=node_info->quantize_error;
2913b2f9ca89786b493edecc00f13c436a003117c441cristy  n=1;
2914b2f9ca89786b493edecc00f13c436a003117c441cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2915b2f9ca89786b493edecc00f13c436a003117c441cristy  for (i=0; i < (ssize_t) number_children ; i++)
2916b2f9ca89786b493edecc00f13c436a003117c441cristy    if (node_info->child[i] != (NodeInfo *) NULL)
29175289eadbd4cd6158bf95bfc78836f3b088d59d9fdirk      n+=QuantizeErrorFlatten(cube_info,node_info->child[i],offset+n,
291806909863026300327af4ae61823f84976a179b9fcristy        quantize_error);
2919b2f9ca89786b493edecc00f13c436a003117c441cristy  return(n);
2920b2f9ca89786b493edecc00f13c436a003117c441cristy}
2921b2f9ca89786b493edecc00f13c436a003117c441cristy
2922b2f9ca89786b493edecc00f13c436a003117c441cristy/*
2923b2f9ca89786b493edecc00f13c436a003117c441cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
2925b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
2926b2f9ca89786b493edecc00f13c436a003117c441cristy%                                                                             %
29273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e d u c e                                                               %
29283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Reduce() traverses the color cube tree and prunes any node whose
29343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  quantization error falls below a particular threshold.
29353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the Reduce method is:
29373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2938f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk%      Reduce(CubeInfo *cube_info,const NodeInfo *node_info)
29393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
29413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
29433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o node_info: pointer to node in color cube tree that is to be pruned.
29453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2947f20fa43474e61817b4b54b490ad3a425ad5ec63bdirkstatic void Reduce(CubeInfo *cube_info,const NodeInfo *node_info)
29483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2949bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
29503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
29513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2952bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
29533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_children;
29543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
29553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
29563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Traverse any children.
29573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
29583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2959bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_children; i++)
29603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (node_info->child[i] != (NodeInfo *) NULL)
2961f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk      Reduce(cube_info,node_info->child[i]);
29623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (node_info->quantize_error <= cube_info->pruning_threshold)
2963f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk    PruneChild(cube_info,node_info);
29643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
29653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
29663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
29673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Find minimum pruning threshold.
29683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
29693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (node_info->number_unique > 0)
29703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->colors++;
29713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (node_info->quantize_error < cube_info->next_threshold)
29723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        cube_info->next_threshold=node_info->quantize_error;
29733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
29743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
29753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
29763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
29773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e d u c e I m a g e C o l o r s                                         %
29823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
29853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ReduceImageColors() repeatedly prunes the tree until the number of nodes
29883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  with n2 > 0 is less than or equal to the maximum number of colors allowed
29893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  in the output image.  On any given iteration over the tree, it selects
29903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  those nodes whose E value is minimal for pruning and merges their
29913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  color statistics upward. It uses a pruning threshold, Ep, to govern
29923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  node selection as follows:
29933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    Ep = 0
29953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    while number of nodes with (n2 > 0) > required maximum number of colors
29963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      prune all nodes such that E <= Ep
29973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Set Ep to minimum E in remaining nodes
29983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
29993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This has the effect of minimizing any quantization error when merging
30003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two nodes together.
30013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  When a node to be pruned has offspring, the pruning procedure invokes
30033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  itself recursively in order to prune the tree from the leaves upward.
30043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
30053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  corresponding data in that node's parent.  This retains the pruned
30063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  node's color characteristics for later averaging.
30073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  For each node, n2 pixels exist for which that node represents the
30093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  smallest volume in RGB space containing those pixel's colors.  When n2
30103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  > 0 the node will uniquely define a color in the output image. At the
30113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
30123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the tree which represent colors present in the input image.
30133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The other pixel count, n1, indicates the total number of colors
30153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  within the cubic volume which the node represents.  This includes n1 -
30163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  n2  pixels whose colors should be defined by nodes at a lower level in
30173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the tree.
30183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ReduceImageColors method is:
30203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      ReduceImageColors(const Image *image,CubeInfo *cube_info)
30223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
30243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
30263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o cube_info: A pointer to the Cube structure.
30283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
30293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3030b2f9ca89786b493edecc00f13c436a003117c441cristy
303109e81245d1499e747d676f1004992619e8d8d664cristystatic int QuantizeErrorCompare(const void *error_p,const void *error_q)
3032b2f9ca89786b493edecc00f13c436a003117c441cristy{
303309e81245d1499e747d676f1004992619e8d8d664cristy  double
3034b2f9ca89786b493edecc00f13c436a003117c441cristy    *p,
3035b2f9ca89786b493edecc00f13c436a003117c441cristy    *q;
3036b2f9ca89786b493edecc00f13c436a003117c441cristy
303709e81245d1499e747d676f1004992619e8d8d664cristy  p=(double *) error_p;
303809e81245d1499e747d676f1004992619e8d8d664cristy  q=(double *) error_q;
3039b2f9ca89786b493edecc00f13c436a003117c441cristy  if (*p > *q)
3040b2f9ca89786b493edecc00f13c436a003117c441cristy    return(1);
304109e81245d1499e747d676f1004992619e8d8d664cristy  if (fabs(*q-*p) <= MagickEpsilon)
3042b2f9ca89786b493edecc00f13c436a003117c441cristy    return(0);
3043b2f9ca89786b493edecc00f13c436a003117c441cristy  return(-1);
3044b2f9ca89786b493edecc00f13c436a003117c441cristy}
3045b2f9ca89786b493edecc00f13c436a003117c441cristy
30463ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void ReduceImageColors(const Image *image,CubeInfo *cube_info)
30473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
30483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define ReduceImageTag  "Reduce/Image"
30493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
30503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
30513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    proceed;
30523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
30533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickOffsetType
30543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset;
30553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3056bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
30573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    span;
30583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
30593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info->next_threshold=0.0;
30604c47510e82ee57609f5a2f30b4263279a3b84462cristy  if (cube_info->colors > cube_info->maximum_colors)
3061b2f9ca89786b493edecc00f13c436a003117c441cristy    {
306209e81245d1499e747d676f1004992619e8d8d664cristy      double
3063b2f9ca89786b493edecc00f13c436a003117c441cristy        *quantize_error;
3064b2f9ca89786b493edecc00f13c436a003117c441cristy
3065b2f9ca89786b493edecc00f13c436a003117c441cristy      /*
3066b2f9ca89786b493edecc00f13c436a003117c441cristy        Enable rapid reduction of the number of unique colors.
3067b2f9ca89786b493edecc00f13c436a003117c441cristy      */
306809e81245d1499e747d676f1004992619e8d8d664cristy      quantize_error=(double *) AcquireQuantumMemory(cube_info->nodes,
3069b2f9ca89786b493edecc00f13c436a003117c441cristy        sizeof(*quantize_error));
307009e81245d1499e747d676f1004992619e8d8d664cristy      if (quantize_error != (double *) NULL)
3071b2f9ca89786b493edecc00f13c436a003117c441cristy        {
30725289eadbd4cd6158bf95bfc78836f3b088d59d9fdirk          (void) QuantizeErrorFlatten(cube_info,cube_info->root,0,
307306909863026300327af4ae61823f84976a179b9fcristy            quantize_error);
307409e81245d1499e747d676f1004992619e8d8d664cristy          qsort(quantize_error,cube_info->nodes,sizeof(double),
307509e81245d1499e747d676f1004992619e8d8d664cristy            QuantizeErrorCompare);
30764c47510e82ee57609f5a2f30b4263279a3b84462cristy          if (cube_info->nodes > (110*(cube_info->maximum_colors+1)/100))
30774c47510e82ee57609f5a2f30b4263279a3b84462cristy            cube_info->next_threshold=quantize_error[cube_info->nodes-110*
30784c47510e82ee57609f5a2f30b4263279a3b84462cristy              (cube_info->maximum_colors+1)/100];
307909e81245d1499e747d676f1004992619e8d8d664cristy          quantize_error=(double *) RelinquishMagickMemory(quantize_error);
3080b2f9ca89786b493edecc00f13c436a003117c441cristy        }
3081b2f9ca89786b493edecc00f13c436a003117c441cristy  }
30823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (span=cube_info->colors; cube_info->colors > cube_info->maximum_colors; )
30833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
30843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->pruning_threshold=cube_info->next_threshold;
30853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->next_threshold=cube_info->root->quantize_error-1;
30863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    cube_info->colors=0;
3087f20fa43474e61817b4b54b490ad3a425ad5ec63bdirk    Reduce(cube_info,cube_info->root);
30883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset=(MagickOffsetType) span-cube_info->colors;
30893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    proceed=SetImageProgress(image,ReduceImageTag,offset,span-
30903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->maximum_colors+1);
30913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (proceed == MagickFalse)
30923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
30933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
30943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
30953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
30963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
30973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
30993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e m a p I m a g e                                                       %
31023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
310709e81245d1499e747d676f1004992619e8d8d664cristy%  RemapImage() replaces the colors of an image with the closest of the colors
310809e81245d1499e747d676f1004992619e8d8d664cristy%  from the reference image.
31093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RemapImage method is:
31113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
3113018f07f7333b25743d0afff892450cebdb905c1acristy%        Image *image,const Image *remap_image,ExceptionInfo *exception)
31143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
31163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
31183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
31203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o remap_image: the reference image.
31223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3123018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
3124018f07f7333b25743d0afff892450cebdb905c1acristy%
31253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
31263ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
3127018f07f7333b25743d0afff892450cebdb905c1acristy  Image *image,const Image *remap_image,ExceptionInfo *exception)
31283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
31293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CubeInfo
31303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cube_info;
31313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
31323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
31333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
31343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
31353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
31363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize color cube.
31373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
31383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
3139e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
31403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
31413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
31423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(remap_image != (Image *) NULL);
3143e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(remap_image->signature == MagickCoreSignature);
314409e81245d1499e747d676f1004992619e8d8d664cristy  assert(exception != (ExceptionInfo *) NULL);
3145e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
31463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
31473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantize_info->number_colors);
31483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info == (CubeInfo *) NULL)
31493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
31503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
31518a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy  status=ClassifyImageColors(cube_info,remap_image,exception);
31523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
31533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
31543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
31553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Classify image colors from the reference image.
31563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
31573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->quantize_info->number_colors=cube_info->colors;
3158018f07f7333b25743d0afff892450cebdb905c1acristy      status=AssignImageColors(image,cube_info,exception);
31593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
31603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DestroyCubeInfo(cube_info);
31613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
31623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
31633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
31643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
31653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e m a p I m a g e s                                                     %
31703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
31733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RemapImages() replaces the colors of a sequence of images with the
31763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  closest color from a reference image.
31773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RemapImage method is:
31793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
3181018f07f7333b25743d0afff892450cebdb905c1acristy%        Image *images,Image *remap_image,ExceptionInfo *exception)
31823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
31843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
31863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o images: the image sequence.
31883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
31893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o remap_image: the reference image.
31903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3191018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
3192018f07f7333b25743d0afff892450cebdb905c1acristy%
31933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
31943ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
3195018f07f7333b25743d0afff892450cebdb905c1acristy  Image *images,const Image *remap_image,ExceptionInfo *exception)
31963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
31973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CubeInfo
31983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *cube_info;
31993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
32013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image;
32023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
32043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
32053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(images != (Image *) NULL);
3207e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(images->signature == MagickCoreSignature);
32083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (images->debug != MagickFalse)
32093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
321009e81245d1499e747d676f1004992619e8d8d664cristy  assert(exception != (ExceptionInfo *) NULL);
3211e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
32123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image=images;
32133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (remap_image == (Image *) NULL)
32143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
32153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
32163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Create a global colormap for an image sequence.
32173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
3218018f07f7333b25743d0afff892450cebdb905c1acristy      status=QuantizeImages(quantize_info,images,exception);
32193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(status);
32203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
32213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
32223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Classify image colors from the reference image.
32233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
32243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
32253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantize_info->number_colors);
32263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (cube_info == (CubeInfo *) NULL)
32273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
32283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
3229018f07f7333b25743d0afff892450cebdb905c1acristy  status=ClassifyImageColors(cube_info,remap_image,exception);
32303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status != MagickFalse)
32313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
32323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
32333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Classify image colors from the reference image.
32343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
32353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      cube_info->quantize_info->number_colors=cube_info->colors;
32363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image=images;
32373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
32383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3239018f07f7333b25743d0afff892450cebdb905c1acristy        status=AssignImageColors(image,cube_info,exception);
32403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
32413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
32423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
32433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
32443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DestroyCubeInfo(cube_info);
32453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
32463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
32473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
32493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t G r a y s c a l e I m a g e                                         %
32543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
32573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
32593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetGrayscaleImage() converts an image to a PseudoClass grayscale image.
32603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
32613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetGrayscaleImage method is:
32623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
326309e81245d1499e747d676f1004992619e8d8d664cristy%      MagickBooleanType SetGrayscaleImage(Image *image,
326409e81245d1499e747d676f1004992619e8d8d664cristy%        ExceptionInfo *exception)
32653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
32663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
32673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
32683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: The image.
32693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3270018f07f7333b25743d0afff892450cebdb905c1acristy%    o exception: return any errors or warnings in this structure.
3271018f07f7333b25743d0afff892450cebdb905c1acristy%
32723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
32733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(__cplusplus) || defined(c_plusplus)
32753ed852eea50f9d4cd633efb8c2b054b8e33c253cristyextern "C" {
32763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
32773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32783ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic int IntensityCompare(const void *x,const void *y)
32793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
328009e81245d1499e747d676f1004992619e8d8d664cristy  double
328109e81245d1499e747d676f1004992619e8d8d664cristy    intensity;
328209e81245d1499e747d676f1004992619e8d8d664cristy
3283101ab708b0574518ac5715da4d3915400e9df79acristy  PixelInfo
32843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *color_1,
32853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *color_2;
32863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3287101ab708b0574518ac5715da4d3915400e9df79acristy  color_1=(PixelInfo *) x;
3288101ab708b0574518ac5715da4d3915400e9df79acristy  color_2=(PixelInfo *) y;
328909e81245d1499e747d676f1004992619e8d8d664cristy  intensity=GetPixelInfoIntensity((const Image *) NULL,color_1)-
329009e81245d1499e747d676f1004992619e8d8d664cristy    GetPixelInfoIntensity((const Image *) NULL,color_2);
3291cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy  return((int) intensity);
32923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
32933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
32943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(__cplusplus) || defined(c_plusplus)
32953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
32963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
32973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3298018f07f7333b25743d0afff892450cebdb905c1acristystatic MagickBooleanType SetGrayscaleImage(Image *image,
3299018f07f7333b25743d0afff892450cebdb905c1acristy  ExceptionInfo *exception)
33003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3301c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
3302c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
3303c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
3304ecc31b159fd21093c91198f7fa26072d288e5230cristy  MagickBooleanType
3305ecc31b159fd21093c91198f7fa26072d288e5230cristy    status;
33063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3307101ab708b0574518ac5715da4d3915400e9df79acristy  PixelInfo
33083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *colormap;
33093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3310bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
33113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
33123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3313ecc31b159fd21093c91198f7fa26072d288e5230cristy  ssize_t
3314ecc31b159fd21093c91198f7fa26072d288e5230cristy    *colormap_index,
3315ecc31b159fd21093c91198f7fa26072d288e5230cristy    j,
3316ecc31b159fd21093c91198f7fa26072d288e5230cristy    y;
33173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
33183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
3319e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
33203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->type != GrayscaleType)
3321e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy    (void) TransformImageColorspace(image,GRAYColorspace,exception);
3322d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk  colormap_index=(ssize_t *) AcquireQuantumMemory(MaxColormapSize,
33233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*colormap_index));
3324bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if (colormap_index == (ssize_t *) NULL)
33253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
33263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
33273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->storage_class != PseudoClass)
33283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3329d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk      (void) ResetMagickMemory(colormap_index,(-1),MaxColormapSize*
3330d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk        sizeof(*colormap_index));
3331d5152401bb219ec1e044fafcb45ebf1cbd77ff11dirk      if (AcquireImageColormap(image,MaxColormapSize,exception) == MagickFalse)
33323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
33333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->filename);
33343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->colors=0;
33353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickTrue;
333646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy      image_view=AcquireAuthenticCacheView(image,exception);
3337b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
3338ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy      #pragma omp parallel for schedule(static,4) shared(status) \
33395e6b259130f9dbe0da4666f734937017babe573acristy        magick_threads(image,image,image->rows,1)
33403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
3341bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0; y < (ssize_t) image->rows; y++)
33423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
33434c08aed51c5899665ade97263692328eea4af106cristy        register Quantum
334405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk          *magick_restrict q;
33453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3346ecc31b159fd21093c91198f7fa26072d288e5230cristy        register ssize_t
3347ecc31b159fd21093c91198f7fa26072d288e5230cristy          x;
3348ecc31b159fd21093c91198f7fa26072d288e5230cristy
33493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
33503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          continue;
33513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
33523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          exception);
3353acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
33543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
33553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            status=MagickFalse;
33563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            continue;
33573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
3358bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0; x < (ssize_t) image->columns; x++)
33593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
3360bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          register size_t
33613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            intensity;
33623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
33634c08aed51c5899665ade97263692328eea4af106cristy          intensity=ScaleQuantumToMap(GetPixelRed(image,q));
33643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (colormap_index[intensity] < 0)
33653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
3366b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
3367ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy              #pragma omp critical (MagickCore_SetGrayscaleImage)
33683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
33693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (colormap_index[intensity] < 0)
33703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                {
3371bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy                  colormap_index[intensity]=(ssize_t) image->colors;
3372e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[image->colors].red=(double)
3373e42f658533644aecb733785ffd91b286d6778deacristy                    GetPixelRed(image,q);
3374e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[image->colors].green=(double)
3375e42f658533644aecb733785ffd91b286d6778deacristy                    GetPixelGreen(image,q);
3376e42f658533644aecb733785ffd91b286d6778deacristy                  image->colormap[image->colors].blue=(double)
3377e42f658533644aecb733785ffd91b286d6778deacristy                    GetPixelBlue(image,q);
33783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  image->colors++;
33793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy               }
33803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
3381aeded788d060ce7a478d88f6fd250732415e8bb9cristy          SetPixelIndex(image,(Quantum) colormap_index[intensity],q);
3382ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy          q+=GetPixelChannels(image);
33833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
33843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
33853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
33863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
33873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image_view=DestroyCacheView(image_view);
33883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3389bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) image->colors; i++)
3390e42f658533644aecb733785ffd91b286d6778deacristy    image->colormap[i].alpha=(double) i;
3391101ab708b0574518ac5715da4d3915400e9df79acristy  qsort((void *) image->colormap,image->colors,sizeof(PixelInfo),
33923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    IntensityCompare);
3393aaaff84e53c6dba4988fc076523eb820fdecd084cristy  colormap=(PixelInfo *) AcquireQuantumMemory(image->colors,sizeof(*colormap));
3394101ab708b0574518ac5715da4d3915400e9df79acristy  if (colormap == (PixelInfo *) NULL)
33953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
33963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
33973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  j=0;
33983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  colormap[j]=image->colormap[0];
3399bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) image->colors; i++)
34003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3401101ab708b0574518ac5715da4d3915400e9df79acristy    if (IsPixelInfoEquivalent(&colormap[j],&image->colormap[i]) == MagickFalse)
34023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
34033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        j++;
34043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        colormap[j]=image->colormap[i];
34053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
34064c08aed51c5899665ade97263692328eea4af106cristy    colormap_index[(ssize_t) image->colormap[i].alpha]=j;
34073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
3408bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  image->colors=(size_t) (j+1);
3409101ab708b0574518ac5715da4d3915400e9df79acristy  image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
34103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->colormap=colormap;
34113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
341246ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
3413b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
3414ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(status) \
34155e6b259130f9dbe0da4666f734937017babe573acristy    magick_threads(image,image,image->rows,1)
34163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
3417bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
34183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
34194c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
342005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
34213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3422ecc31b159fd21093c91198f7fa26072d288e5230cristy    register ssize_t
3423ecc31b159fd21093c91198f7fa26072d288e5230cristy      x;
3424ecc31b159fd21093c91198f7fa26072d288e5230cristy
34253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
34263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      continue;
34273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3428acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy    if (q == (Quantum *) NULL)
34293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
34303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickFalse;
34313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        continue;
34323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3433bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
34344c08aed51c5899665ade97263692328eea4af106cristy    {
34354c08aed51c5899665ade97263692328eea4af106cristy      SetPixelIndex(image,(Quantum) colormap_index[ScaleQuantumToMap(
34364c08aed51c5899665ade97263692328eea4af106cristy        GetPixelIndex(image,q))],q);
3437ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
34384c08aed51c5899665ade97263692328eea4af106cristy    }
34393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
34403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickFalse;
34413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
34423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
3443bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
34443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->type=GrayscaleType;
3445f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk  if (SetImageMonochrome(image,exception) != MagickFalse)
34463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->type=BilevelType;
34473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
34483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3449