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