]> granicus.if.org Git - imagemagick/blob - magick/color.c
(no commit message)
[imagemagick] / magick / color.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                       CCCC   OOO   L       OOO   RRRR                       %
6 %                      C      O   O  L      O   O  R   R                      %
7 %                      C      O   O  L      O   O  RRRR                       %
8 %                      C      O   O  L      O   O  R R                        %
9 %                       CCCC   OOO   LLLLL   OOO   R  R                       %
10 %                                                                             %
11 %                                                                             %
12 %                          MagickCore Color Methods                           %
13 %                                                                             %
14 %                              Software Design                                %
15 %                                John Cristy                                  %
16 %                                 July 1992                                   %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %  We use linked-lists because splay-trees do not currently support duplicate
36 %  key / value pairs (.e.g X11 green compliance and SVG green compliance).
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "magick/studio.h"
44 #include "magick/blob.h"
45 #include "magick/cache-view.h"
46 #include "magick/cache.h"
47 #include "magick/color.h"
48 #include "magick/color-private.h"
49 #include "magick/client.h"
50 #include "magick/configure.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/gem.h"
54 #include "magick/geometry.h"
55 #include "magick/image-private.h"
56 #include "magick/memory_.h"
57 #include "magick/monitor.h"
58 #include "magick/monitor-private.h"
59 #include "magick/option.h"
60 #include "magick/pixel-private.h"
61 #include "magick/quantize.h"
62 #include "magick/quantum.h"
63 #include "magick/semaphore.h"
64 #include "magick/string_.h"
65 #include "magick/token.h"
66 #include "magick/utility.h"
67 #include "magick/xml-tree.h"
68 \f
69 /*
70   Define declarations.
71 */
72 #define ColorFilename  "colors.xml"
73 #define MaxTreeDepth  8
74 #define NodesInAList  1536
75 \f
76 /*
77   Declare color map.
78 */
79 static const char
80   *ColorMap = (const char *)
81     "<?xml version=\"1.0\"?>"
82     "<colormap>"
83     "  <color name=\"none\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
84     "  <color name=\"black\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11, XPM\" />"
85     "  <color name=\"red\" color=\"rgb(255,0,0)\" compliance=\"SVG, X11, XPM\" />"
86     "  <color name=\"magenta\" color=\"rgb(255,0,255)\" compliance=\"SVG, X11, XPM\" />"
87     "  <color name=\"green\" color=\"rgb(0,128,0)\" compliance=\"SVG\" />"
88     "  <color name=\"cyan\" color=\"rgb(0,255,255)\" compliance=\"SVG, X11, XPM\" />"
89     "  <color name=\"blue\" color=\"rgb(0,0,255)\" compliance=\"SVG, X11, XPM\" />"
90     "  <color name=\"yellow\" color=\"rgb(255,255,0)\" compliance=\"SVG, X11, XPM\" />"
91     "  <color name=\"white\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
92     "  <color name=\"AliceBlue\" color=\"rgb(240,248,255)\" compliance=\"SVG, X11, XPM\" />"
93     "  <color name=\"AntiqueWhite\" color=\"rgb(250,235,215)\" compliance=\"SVG, X11, XPM\" />"
94     "  <color name=\"aqua\" color=\"rgb(0,255,255)\" compliance=\"SVG\" />"
95     "  <color name=\"aquamarine\" color=\"rgb(127,255,212)\" compliance=\"SVG, X11, XPM\" />"
96     "  <color name=\"azure\" color=\"rgb(240,255,255)\" compliance=\"SVG, X11, XPM\" />"
97     "  <color name=\"beige\" color=\"rgb(245,245,220)\" compliance=\"SVG, X11, XPM\" />"
98     "  <color name=\"bisque\" color=\"rgb(255,228,196)\" compliance=\"SVG, X11, XPM\" />"
99     "  <color name=\"BlanchedAlmond\" color=\"rgb(255,235,205)\" compliance=\"SVG, X11, XPM\" />"
100     "  <color name=\"BlueViolet\" color=\"rgb(138,43,226)\" compliance=\"SVG, X11, XPM\" />"
101     "  <color name=\"brown\" color=\"rgb(165,42,42)\" compliance=\"SVG, X11, XPM\" />"
102     "  <color name=\"burlywood\" color=\"rgb(222,184,135)\" compliance=\"SVG, X11, XPM\" />"
103     "  <color name=\"CadetBlue\" color=\"rgb(95,158,160)\" compliance=\"SVG, X11, XPM\" />"
104     "  <color name=\"chartreuse\" color=\"rgb(127,255,0)\" compliance=\"SVG, X11, XPM\" />"
105     "  <color name=\"chocolate\" color=\"rgb(210,105,30)\" compliance=\"SVG, X11, XPM\" />"
106     "  <color name=\"coral\" color=\"rgb(255,127,80)\" compliance=\"SVG, X11, XPM\" />"
107     "  <color name=\"CornflowerBlue\" color=\"rgb(100,149,237)\" compliance=\"SVG, X11, XPM\" />"
108     "  <color name=\"cornsilk\" color=\"rgb(255,248,220)\" compliance=\"SVG, X11, XPM\" />"
109     "  <color name=\"crimson\" color=\"rgb(220,20,60)\" compliance=\"SVG\" />"
110     "  <color name=\"DarkBlue\" color=\"rgb(0,0,139)\" compliance=\"SVG, X11\" />"
111     "  <color name=\"DarkCyan\" color=\"rgb(0,139,139)\" compliance=\"SVG, X11\" />"
112     "  <color name=\"DarkGoldenrod\" color=\"rgb(184,134,11)\" compliance=\"SVG, X11, XPM\" />"
113     "  <color name=\"DarkGray\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
114     "  <color name=\"DarkGreen\" color=\"rgb(0,100,0)\" compliance=\"SVG, X11, XPM\" />"
115     "  <color name=\"DarkGrey\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
116     "  <color name=\"DarkKhaki\" color=\"rgb(189,183,107)\" compliance=\"SVG, X11, XPM\" />"
117     "  <color name=\"DarkMagenta\" color=\"rgb(139,0,139)\" compliance=\"SVG, X11\" />"
118     "  <color name=\"DarkOliveGreen\" color=\"rgb(85,107,47)\" compliance=\"SVG, X11, XPM\" />"
119     "  <color name=\"DarkOrange\" color=\"rgb(255,140,0)\" compliance=\"SVG, X11, XPM\" />"
120     "  <color name=\"DarkOrchid\" color=\"rgb(153,50,204)\" compliance=\"SVG, X11, XPM\" />"
121     "  <color name=\"DarkRed\" color=\"rgb(139,0,0)\" compliance=\"SVG, X11\" />"
122     "  <color name=\"DarkSalmon\" color=\"rgb(233,150,122)\" compliance=\"SVG, X11, XPM\" />"
123     "  <color name=\"DarkSeaGreen\" color=\"rgb(143,188,143)\" compliance=\"SVG, X11, XPM\" />"
124     "  <color name=\"DarkSlateBlue\" color=\"rgb(72,61,139)\" compliance=\"SVG, X11, XPM\" />"
125     "  <color name=\"DarkSlateGray\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11, XPM\" />"
126     "  <color name=\"DarkSlateGrey\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11\" />"
127     "  <color name=\"DarkTurquoise\" color=\"rgb(0,206,209)\" compliance=\"SVG, X11, XPM\" />"
128     "  <color name=\"DarkViolet\" color=\"rgb(148,0,211)\" compliance=\"SVG, X11, XPM\" />"
129     "  <color name=\"DeepPink\" color=\"rgb(255,20,147)\" compliance=\"SVG, X11, XPM\" />"
130     "  <color name=\"DeepSkyBlue\" color=\"rgb(0,191,255)\" compliance=\"SVG, X11, XPM\" />"
131     "  <color name=\"DimGray\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11, XPM\" />"
132     "  <color name=\"DimGrey\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
133     "  <color name=\"DodgerBlue\" color=\"rgb(30,144,255)\" compliance=\"SVG, X11, XPM\" />"
134     "  <color name=\"firebrick\" color=\"rgb(178,34,34)\" compliance=\"SVG, X11, XPM\" />"
135     "  <color name=\"FloralWhite\" color=\"rgb(255,250,240)\" compliance=\"SVG, X11, XPM\" />"
136     "  <color name=\"ForestGreen\" color=\"rgb(34,139,34)\" compliance=\"SVG, X11, XPM\" />"
137     "  <color name=\"fractal\" color=\"rgb(128,128,128)\" compliance=\"SVG\" />"
138     "  <color name=\"fuchsia\" color=\"rgb(255,0,255)\" compliance=\"SVG\" />"
139     "  <color name=\"gainsboro\" color=\"rgb(220,220,220)\" compliance=\"SVG, X11, XPM\" />"
140     "  <color name=\"GhostWhite\" color=\"rgb(248,248,255)\" compliance=\"SVG, X11, XPM\" />"
141     "  <color name=\"gold\" color=\"rgb(255,215,0)\" compliance=\"X11, XPM\" />"
142     "  <color name=\"goldenrod\" color=\"rgb(218,165,32)\" compliance=\"SVG, X11, XPM\" />"
143     "  <color name=\"gray\" color=\"rgb(126,126,126)\" compliance=\"SVG\" />"
144     "  <color name=\"gray74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
145     "  <color name=\"gray100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
146     "  <color name=\"grey\" color=\"rgb(190,190,190)\" compliance=\"SVG, X11\" />"
147     "  <color name=\"grey0\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11\" />"
148     "  <color name=\"grey1\" color=\"rgb(3,3,3)\" compliance=\"SVG, X11\" />"
149     "  <color name=\"grey10\" color=\"rgb(26,26,26)\" compliance=\"SVG, X11\" />"
150     "  <color name=\"grey100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
151     "  <color name=\"grey11\" color=\"rgb(28,28,28)\" compliance=\"SVG, X11\" />"
152     "  <color name=\"grey12\" color=\"rgb(31,31,31)\" compliance=\"SVG, X11\" />"
153     "  <color name=\"grey13\" color=\"rgb(33,33,33)\" compliance=\"SVG, X11\" />"
154     "  <color name=\"grey14\" color=\"rgb(36,36,36)\" compliance=\"SVG, X11\" />"
155     "  <color name=\"grey15\" color=\"rgb(38,38,38)\" compliance=\"SVG, X11\" />"
156     "  <color name=\"grey16\" color=\"rgb(41,41,41)\" compliance=\"SVG, X11\" />"
157     "  <color name=\"grey17\" color=\"rgb(43,43,43)\" compliance=\"SVG, X11\" />"
158     "  <color name=\"grey18\" color=\"rgb(45,45,45)\" compliance=\"SVG, X11\" />"
159     "  <color name=\"grey19\" color=\"rgb(48,48,48)\" compliance=\"SVG, X11\" />"
160     "  <color name=\"grey2\" color=\"rgb(5,5,5)\" compliance=\"SVG, X11\" />"
161     "  <color name=\"grey20\" color=\"rgb(51,51,51)\" compliance=\"SVG, X11\" />"
162     "  <color name=\"grey21\" color=\"rgb(54,54,54)\" compliance=\"SVG, X11\" />"
163     "  <color name=\"grey22\" color=\"rgb(56,56,56)\" compliance=\"SVG, X11\" />"
164     "  <color name=\"grey23\" color=\"rgb(59,59,59)\" compliance=\"SVG, X11\" />"
165     "  <color name=\"grey24\" color=\"rgb(61,61,61)\" compliance=\"SVG, X11\" />"
166     "  <color name=\"grey25\" color=\"rgb(64,64,64)\" compliance=\"SVG, X11\" />"
167     "  <color name=\"grey26\" color=\"rgb(66,66,66)\" compliance=\"SVG, X11\" />"
168     "  <color name=\"grey27\" color=\"rgb(69,69,69)\" compliance=\"SVG, X11\" />"
169     "  <color name=\"grey28\" color=\"rgb(71,71,71)\" compliance=\"SVG, X11\" />"
170     "  <color name=\"grey29\" color=\"rgb(74,74,74)\" compliance=\"SVG, X11\" />"
171     "  <color name=\"grey3\" color=\"rgb(8,8,8)\" compliance=\"SVG, X11\" />"
172     "  <color name=\"grey30\" color=\"rgb(77,77,77)\" compliance=\"SVG, X11\" />"
173     "  <color name=\"grey31\" color=\"rgb(79,79,79)\" compliance=\"SVG, X11\" />"
174     "  <color name=\"grey32\" color=\"rgb(82,82,82)\" compliance=\"SVG, X11\" />"
175     "  <color name=\"grey33\" color=\"rgb(84,84,84)\" compliance=\"SVG, X11\" />"
176     "  <color name=\"grey34\" color=\"rgb(87,87,87)\" compliance=\"SVG, X11\" />"
177     "  <color name=\"grey35\" color=\"rgb(89,89,89)\" compliance=\"SVG, X11\" />"
178     "  <color name=\"grey36\" color=\"rgb(92,92,92)\" compliance=\"SVG, X11\" />"
179     "  <color name=\"grey37\" color=\"rgb(94,94,94)\" compliance=\"SVG, X11\" />"
180     "  <color name=\"grey38\" color=\"rgb(97,97,97)\" compliance=\"SVG, X11\" />"
181     "  <color name=\"grey39\" color=\"rgb(99,99,99)\" compliance=\"SVG, X11\" />"
182     "  <color name=\"grey4\" color=\"rgb(10,10,10)\" compliance=\"SVG, X11\" />"
183     "  <color name=\"grey40\" color=\"rgb(102,102,102)\" compliance=\"SVG, X11\" />"
184     "  <color name=\"grey41\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
185     "  <color name=\"grey42\" color=\"rgb(107,107,107)\" compliance=\"SVG, X11\" />"
186     "  <color name=\"grey43\" color=\"rgb(110,110,110)\" compliance=\"SVG, X11\" />"
187     "  <color name=\"grey44\" color=\"rgb(112,112,112)\" compliance=\"SVG, X11\" />"
188     "  <color name=\"grey45\" color=\"rgb(115,115,115)\" compliance=\"SVG, X11\" />"
189     "  <color name=\"grey45\" color=\"rgb(117,117,117)\" compliance=\"SVG, X11\" />"
190     "  <color name=\"grey47\" color=\"rgb(120,120,120)\" compliance=\"SVG, X11\" />"
191     "  <color name=\"grey48\" color=\"rgb(122,122,122)\" compliance=\"SVG, X11\" />"
192     "  <color name=\"grey49\" color=\"rgb(125,125,125)\" compliance=\"SVG, X11\" />"
193     "  <color name=\"grey5\" color=\"rgb(13,13,13)\" compliance=\"SVG, X11\" />"
194     "  <color name=\"grey50\" color=\"rgb(50%,50%,50%)\" compliance=\"SVG, X11\" />"
195     "  <color name=\"grey51\" color=\"rgb(130,130,130)\" compliance=\"SVG, X11\" />"
196     "  <color name=\"grey52\" color=\"rgb(133,133,133)\" compliance=\"SVG, X11\" />"
197     "  <color name=\"grey53\" color=\"rgb(135,135,135)\" compliance=\"SVG, X11\" />"
198     "  <color name=\"grey54\" color=\"rgb(138,138,138)\" compliance=\"SVG, X11\" />"
199     "  <color name=\"grey55\" color=\"rgb(140,140,140)\" compliance=\"SVG, X11\" />"
200     "  <color name=\"grey56\" color=\"rgb(143,143,143)\" compliance=\"SVG, X11\" />"
201     "  <color name=\"grey57\" color=\"rgb(145,145,145)\" compliance=\"SVG, X11\" />"
202     "  <color name=\"grey58\" color=\"rgb(148,148,148)\" compliance=\"SVG, X11\" />"
203     "  <color name=\"grey59\" color=\"rgb(150,150,150)\" compliance=\"SVG, X11\" />"
204     "  <color name=\"grey6\" color=\"rgb(15,15,15)\" compliance=\"SVG, X11\" />"
205     "  <color name=\"grey60\" color=\"rgb(153,153,153)\" compliance=\"SVG, X11\" />"
206     "  <color name=\"grey61\" color=\"rgb(156,156,156)\" compliance=\"SVG, X11\" />"
207     "  <color name=\"grey62\" color=\"rgb(158,158,158)\" compliance=\"SVG, X11\" />"
208     "  <color name=\"grey63\" color=\"rgb(161,161,161)\" compliance=\"SVG, X11\" />"
209     "  <color name=\"grey64\" color=\"rgb(163,163,163)\" compliance=\"SVG, X11\" />"
210     "  <color name=\"grey65\" color=\"rgb(166,166,166)\" compliance=\"SVG, X11\" />"
211     "  <color name=\"grey66\" color=\"rgb(168,168,168)\" compliance=\"SVG, X11\" />"
212     "  <color name=\"grey67\" color=\"rgb(171,171,171)\" compliance=\"SVG, X11\" />"
213     "  <color name=\"grey68\" color=\"rgb(173,173,173)\" compliance=\"SVG, X11\" />"
214     "  <color name=\"grey69\" color=\"rgb(176,176,176)\" compliance=\"SVG, X11\" />"
215     "  <color name=\"grey7\" color=\"rgb(18,18,18)\" compliance=\"SVG, X11\" />"
216     "  <color name=\"grey70\" color=\"rgb(179,179,179)\" compliance=\"SVG, X11\" />"
217     "  <color name=\"grey71\" color=\"rgb(181,181,181)\" compliance=\"SVG, X11\" />"
218     "  <color name=\"grey72\" color=\"rgb(184,184,184)\" compliance=\"SVG, X11\" />"
219     "  <color name=\"grey73\" color=\"rgb(186,186,186)\" compliance=\"SVG, X11\" />"
220     "  <color name=\"grey74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
221     "  <color name=\"grey75\" color=\"rgb(191,191,191)\" compliance=\"SVG, X11\" />"
222     "  <color name=\"grey76\" color=\"rgb(194,194,194)\" compliance=\"SVG, X11\" />"
223     "  <color name=\"grey77\" color=\"rgb(196,196,196)\" compliance=\"SVG, X11\" />"
224     "  <color name=\"grey78\" color=\"rgb(199,199,199)\" compliance=\"SVG, X11\" />"
225     "  <color name=\"grey79\" color=\"rgb(201,201,201)\" compliance=\"SVG, X11\" />"
226     "  <color name=\"grey8\" color=\"rgb(20,20,20)\" compliance=\"SVG, X11\" />"
227     "  <color name=\"grey80\" color=\"rgb(204,204,204)\" compliance=\"SVG, X11\" />"
228     "  <color name=\"grey81\" color=\"rgb(207,207,207)\" compliance=\"SVG, X11\" />"
229     "  <color name=\"grey82\" color=\"rgb(209,209,209)\" compliance=\"SVG, X11\" />"
230     "  <color name=\"grey83\" color=\"rgb(212,212,212)\" compliance=\"SVG, X11\" />"
231     "  <color name=\"grey84\" color=\"rgb(214,214,214)\" compliance=\"SVG, X11\" />"
232     "  <color name=\"grey85\" color=\"rgb(217,217,217)\" compliance=\"SVG, X11\" />"
233     "  <color name=\"grey86\" color=\"rgb(219,219,219)\" compliance=\"SVG, X11\" />"
234     "  <color name=\"grey87\" color=\"rgb(222,222,222)\" compliance=\"SVG, X11\" />"
235     "  <color name=\"grey88\" color=\"rgb(224,224,224)\" compliance=\"SVG, X11\" />"
236     "  <color name=\"grey89\" color=\"rgb(227,227,227)\" compliance=\"SVG, X11\" />"
237     "  <color name=\"grey9\" color=\"rgb(23,23,23)\" compliance=\"SVG, X11\" />"
238     "  <color name=\"grey90\" color=\"rgb(229,229,229)\" compliance=\"SVG, X11\" />"
239     "  <color name=\"grey91\" color=\"rgb(232,232,232)\" compliance=\"SVG, X11\" />"
240     "  <color name=\"grey92\" color=\"rgb(235,235,235)\" compliance=\"SVG, X11\" />"
241     "  <color name=\"grey93\" color=\"rgb(237,237,237)\" compliance=\"SVG, X11\" />"
242     "  <color name=\"grey94\" color=\"rgb(240,240,240)\" compliance=\"SVG, X11\" />"
243     "  <color name=\"grey95\" color=\"rgb(242,242,242)\" compliance=\"SVG, X11\" />"
244     "  <color name=\"grey96\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11\" />"
245     "  <color name=\"grey97\" color=\"rgb(247,247,247)\" compliance=\"SVG, X11\" />"
246     "  <color name=\"grey98\" color=\"rgb(250,250,250)\" compliance=\"SVG, X11\" />"
247     "  <color name=\"grey99\" color=\"rgb(252,252,252)\" compliance=\"SVG, X11\" />"
248     "  <color name=\"honeydew\" color=\"rgb(240,255,240)\" compliance=\"SVG, X11, XPM\" />"
249     "  <color name=\"HotPink\" color=\"rgb(255,105,180)\" compliance=\"SVG, X11, XPM\" />"
250     "  <color name=\"IndianRed\" color=\"rgb(205,92,92)\" compliance=\"SVG, X11, XPM\" />"
251     "  <color name=\"indigo\" color=\"rgb(75,0,130)\" compliance=\"SVG\" />"
252     "  <color name=\"ivory\" color=\"rgb(255,255,240)\" compliance=\"SVG, X11, XPM\" />"
253     "  <color name=\"khaki\" color=\"rgb(240,230,140)\" compliance=\"SVG, X11, XPM\" />"
254     "  <color name=\"lavender\" color=\"rgb(230,230,250)\" compliance=\"SVG, X11, XPM\" />"
255     "  <color name=\"LavenderBlush\" color=\"rgb(255,240,245)\" compliance=\"SVG, X11, XPM\" />"
256     "  <color name=\"LawnGreen\" color=\"rgb(124,252,0)\" compliance=\"SVG, X11, XPM\" />"
257     "  <color name=\"LemonChiffon\" color=\"rgb(255,250,205)\" compliance=\"SVG, X11, XPM\" />"
258     "  <color name=\"LightBlue\" color=\"rgb(173,216,230)\" compliance=\"SVG, X11, XPM\" />"
259     "  <color name=\"LightCoral\" color=\"rgb(240,128,128)\" compliance=\"SVG, X11, XPM\" />"
260     "  <color name=\"LightCyan\" color=\"rgb(224,255,255)\" compliance=\"SVG, X11, XPM\" />"
261     "  <color name=\"LightGoldenrodYellow\" color=\"rgb(250,250,210)\" compliance=\"SVG, X11, XPM\" />"
262     "  <color name=\"LightGray\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11, XPM\" />"
263     "  <color name=\"LightGreen\" color=\"rgb(144,238,144)\" compliance=\"SVG, X11\" />"
264     "  <color name=\"LightGrey\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11\" />"
265     "  <color name=\"LightPink\" color=\"rgb(255,182,193)\" compliance=\"SVG, X11, XPM\" />"
266     "  <color name=\"LightSalmon\" color=\"rgb(255,160,122)\" compliance=\"SVG, X11, XPM\" />"
267     "  <color name=\"LightSeaGreen\" color=\"rgb(32,178,170)\" compliance=\"SVG, X11, XPM\" />"
268     "  <color name=\"LightSkyBlue\" color=\"rgb(135,206,250)\" compliance=\"SVG, X11, XPM\" />"
269     "  <color name=\"LightSlateGray\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11, XPM\" />"
270     "  <color name=\"LightSlateGrey\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11\" />"
271     "  <color name=\"LightSteelBlue\" color=\"rgb(176,196,222)\" compliance=\"SVG, X11, XPM\" />"
272     "  <color name=\"LightYellow\" color=\"rgb(255,255,224)\" compliance=\"SVG, X11, XPM\" />"
273     "  <color name=\"lime\" color=\"rgb(0,255,0)\" compliance=\"SVG\" />"
274     "  <color name=\"LimeGreen\" color=\"rgb(50,205,50)\" compliance=\"SVG, X11, XPM\" />"
275     "  <color name=\"linen\" color=\"rgb(250,240,230)\" compliance=\"SVG, X11, XPM\" />"
276     "  <color name=\"maroon\" color=\"rgb(128,0,0)\" compliance=\"SVG\" />"
277     "  <color name=\"MediumAquamarine\" color=\"rgb(102,205,170)\" compliance=\"SVG, X11, XPM\" />"
278     "  <color name=\"MediumBlue\" color=\"rgb(0,0,205)\" compliance=\"SVG, X11, XPM\" />"
279     "  <color name=\"MediumOrchid\" color=\"rgb(186,85,211)\" compliance=\"SVG, X11, XPM\" />"
280     "  <color name=\"MediumPurple\" color=\"rgb(147,112,219)\" compliance=\"SVG, X11, XPM\" />"
281     "  <color name=\"MediumSeaGreen\" color=\"rgb(60,179,113)\" compliance=\"SVG, X11, XPM\" />"
282     "  <color name=\"MediumSlateBlue\" color=\"rgb(123,104,238)\" compliance=\"SVG, X11, XPM\" />"
283     "  <color name=\"MediumSpringGreen\" color=\"rgb(0,250,154)\" compliance=\"SVG, X11, XPM\" />"
284     "  <color name=\"MediumTurquoise\" color=\"rgb(72,209,204)\" compliance=\"SVG, X11, XPM\" />"
285     "  <color name=\"MediumVioletRed\" color=\"rgb(199,21,133)\" compliance=\"SVG, X11, XPM\" />"
286     "  <color name=\"MidnightBlue\" color=\"rgb(25,25,112)\" compliance=\"SVG, X11, XPM\" />"
287     "  <color name=\"MintCream\" color=\"rgb(245,255,250)\" compliance=\"SVG, X11, XPM\" />"
288     "  <color name=\"MistyRose\" color=\"rgb(255,228,225)\" compliance=\"SVG, X11, XPM\" />"
289     "  <color name=\"moccasin\" color=\"rgb(255,228,181)\" compliance=\"SVG, X11, XPM\" />"
290     "  <color name=\"NavajoWhite\" color=\"rgb(255,222,173)\" compliance=\"SVG, X11, XPM\" />"
291     "  <color name=\"navy\" color=\"rgb(0,0,128)\" compliance=\"SVG, X11, XPM\" />"
292     "  <color name=\"matte\" color=\"rgb(0,0,0,0)\" compliance=\"SVG\" />"
293     "  <color name=\"OldLace\" color=\"rgb(253,245,230)\" compliance=\"SVG, X11, XPM\" />"
294     "  <color name=\"olive\" color=\"rgb(128,128,0)\" compliance=\"SVG\" />"
295     "  <color name=\"OliveDrab\" color=\"rgb(107,142,35)\" compliance=\"SVG, X11, XPM\" />"
296     "  <color name=\"opaque\" color=\"rgb(0,0,0)\" compliance=\"SVG\" />"
297     "  <color name=\"orange\" color=\"rgb(255,165,0)\" compliance=\"SVG, X11, XPM\" />"
298     "  <color name=\"OrangeRed\" color=\"rgb(255,69,0)\" compliance=\"SVG, X11, XPM\" />"
299     "  <color name=\"orchid\" color=\"rgb(218,112,214)\" compliance=\"SVG, X11, XPM\" />"
300     "  <color name=\"PaleGoldenrod\" color=\"rgb(238,232,170)\" compliance=\"SVG, X11, XPM\" />"
301     "  <color name=\"PaleGreen\" color=\"rgb(152,251,152)\" compliance=\"SVG, X11, XPM\" />"
302     "  <color name=\"PaleTurquoise\" color=\"rgb(175,238,238)\" compliance=\"SVG, X11, XPM\" />"
303     "  <color name=\"PaleVioletRed\" color=\"rgb(219,112,147)\" compliance=\"SVG, X11, XPM\" />"
304     "  <color name=\"PapayaWhip\" color=\"rgb(255,239,213)\" compliance=\"SVG, X11, XPM\" />"
305     "  <color name=\"PeachPuff\" color=\"rgb(255,218,185)\" compliance=\"SVG, X11, XPM\" />"
306     "  <color name=\"peru\" color=\"rgb(205,133,63)\" compliance=\"SVG, X11, XPM\" />"
307     "  <color name=\"pink\" color=\"rgb(255,192,203)\" compliance=\"SVG, X11, XPM\" />"
308     "  <color name=\"plum\" color=\"rgb(221,160,221)\" compliance=\"SVG, X11, XPM\" />"
309     "  <color name=\"PowderBlue\" color=\"rgb(176,224,230)\" compliance=\"SVG, X11, XPM\" />"
310     "  <color name=\"purple\" color=\"rgb(128,0,128)\" compliance=\"SVG\" />"
311     "  <color name=\"RosyBrown\" color=\"rgb(188,143,143)\" compliance=\"SVG, X11, XPM\" />"
312     "  <color name=\"RoyalBlue\" color=\"rgb(65,105,225)\" compliance=\"SVG, X11, XPM\" />"
313     "  <color name=\"SaddleBrown\" color=\"rgb(139,69,19)\" compliance=\"SVG, X11, XPM\" />"
314     "  <color name=\"salmon\" color=\"rgb(250,128,114)\" compliance=\"SVG, X11, XPM\" />"
315     "  <color name=\"SandyBrown\" color=\"rgb(244,164,96)\" compliance=\"SVG, X11, XPM\" />"
316     "  <color name=\"SeaGreen\" color=\"rgb(45,139,87)\" compliance=\"SVG, X11, XPM\" />"
317     "  <color name=\"seashell\" color=\"rgb(255,245,238)\" compliance=\"SVG, X11, XPM\" />"
318     "  <color name=\"sienna\" color=\"rgb(160,82,45)\" compliance=\"SVG, X11, XPM\" />"
319     "  <color name=\"silver\" color=\"rgb(192,192,192)\" compliance=\"SVG\" />"
320     "  <color name=\"SkyBlue\" color=\"rgb(135,206,235)\" compliance=\"SVG, X11, XPM\" />"
321     "  <color name=\"SlateBlue\" color=\"rgb(106,90,205)\" compliance=\"SVG, X11, XPM\" />"
322     "  <color name=\"SlateGray\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11, XPM\" />"
323     "  <color name=\"SlateGrey\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11\" />"
324     "  <color name=\"snow\" color=\"rgb(255,250,250)\" compliance=\"SVG, X11, XPM\" />"
325     "  <color name=\"SpringGreen\" color=\"rgb(0,255,127)\" compliance=\"SVG, X11, XPM\" />"
326     "  <color name=\"SteelBlue\" color=\"rgb(70,130,180)\" compliance=\"SVG, X11, XPM\" />"
327     "  <color name=\"tan\" color=\"rgb(210,180,140)\" compliance=\"SVG, X11, XPM\" />"
328     "  <color name=\"teal\" color=\"rgb(0,128,128)\" compliance=\"SVG\" />"
329     "  <color name=\"thistle\" color=\"rgb(216,191,216)\" compliance=\"SVG, X11, XPM\" />"
330     "  <color name=\"tomato\" color=\"rgb(255,99,71)\" compliance=\"SVG, X11, XPM\" />"
331     "  <color name=\"transparent\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
332     "  <color name=\"turquoise\" color=\"rgb(64,224,208)\" compliance=\"SVG, X11, XPM\" />"
333     "  <color name=\"violet\" color=\"rgb(238,130,238)\" compliance=\"SVG, X11, XPM\" />"
334     "  <color name=\"wheat\" color=\"rgb(245,222,179)\" compliance=\"SVG, X11, XPM\" />"
335     "  <color name=\"WhiteSmoke\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11, XPM\" />"
336     "  <color name=\"YellowGreen\" color=\"rgb(154,205,50)\" compliance=\"SVG, X11, XPM\" />"
337     "</colormap>";
338 \f
339 /*
340   Typedef declarations.
341 */
342 typedef struct _NodeInfo
343 {
344   struct _NodeInfo
345     *child[16];
346
347   ColorPacket
348     *list;
349
350   MagickSizeType
351     number_unique;
352
353   unsigned long
354     level;
355 } NodeInfo;
356
357 typedef struct _Nodes
358 {
359   NodeInfo
360     nodes[NodesInAList];
361
362   struct _Nodes
363     *next;
364 } Nodes;
365
366 typedef struct _CubeInfo
367 {
368   NodeInfo
369     *root;
370
371   long
372     x,
373     progress;
374
375   unsigned long
376     colors,
377     free_nodes;
378
379   NodeInfo
380     *node_info;
381
382   Nodes
383     *node_queue;
384 } CubeInfo;
385 \f
386 /*
387   Static declarations.
388 */
389 static LinkedListInfo
390   *color_list = (LinkedListInfo *) NULL;
391
392 static SemaphoreInfo
393   *color_semaphore = (SemaphoreInfo *) NULL;
394
395 static volatile MagickBooleanType
396   instantiate_color = MagickFalse;
397 \f
398 /*
399   Forward declarations.
400 */
401 static CubeInfo
402   *GetCubeInfo(void);
403
404 static NodeInfo
405   *GetNodeInfo(CubeInfo *,const unsigned long);
406
407 static MagickBooleanType
408   InitializeColorList(ExceptionInfo *),
409   LoadColorLists(const char *,ExceptionInfo *);
410
411 static void
412   DestroyColorCube(const Image *,NodeInfo *);
413 \f
414 /*
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416 %                                                                             %
417 %                                                                             %
418 %                                                                             %
419 +   C l a s s i f y I m a g e C o l o r s                                     %
420 %                                                                             %
421 %                                                                             %
422 %                                                                             %
423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424 %
425 %  ClassifyImageColors() builds a populated CubeInfo tree for the specified
426 %  image.  The returned tree should be deallocated using DestroyCubeInfo()
427 %  once it is no longer needed.
428 %
429 %  The format of the ClassifyImageColors() method is:
430 %
431 %      CubeInfo *ClassifyImageColors(const Image *image,
432 %        ExceptionInfo *exception)
433 %
434 %  A description of each parameter follows.
435 %
436 %    o image: the image.
437 %
438 %    o exception: return any errors or warnings in this structure.
439 %
440 */
441
442 static inline unsigned long ColorToNodeId(const Image *image,
443   const MagickPixelPacket *pixel,unsigned long index)
444 {
445   unsigned long
446     id;
447
448   id=(unsigned long) (
449     ((ScaleQuantumToChar(RoundToQuantum(pixel->red)) >> index) & 0x01) |
450     ((ScaleQuantumToChar(RoundToQuantum(pixel->green)) >> index) & 0x01) << 1 |
451     ((ScaleQuantumToChar(RoundToQuantum(pixel->blue)) >> index) & 0x01) << 2);
452   if (image->matte != MagickFalse)
453     id|=((ScaleQuantumToChar(RoundToQuantum(pixel->opacity)) >> index) &
454       0x01) << 3;
455   return(id);
456 }
457
458 static CubeInfo *ClassifyImageColors(const Image *image,
459   ExceptionInfo *exception)
460 {
461 #define EvaluateImageTag  "  Compute image colors...  "
462
463   CubeInfo
464     *cube_info;
465
466   long
467     y;
468
469   MagickBooleanType
470     proceed;
471
472   MagickPixelPacket
473     pixel,
474     target;
475
476   NodeInfo
477     *node_info;
478
479   register const IndexPacket
480     *indexes;
481
482   register const PixelPacket
483     *p;
484
485   register long
486     i,
487     x;
488
489   register unsigned long
490     id,
491     index,
492     level;
493
494   CacheView
495     *image_view;
496
497   /*
498     Initialize color description tree.
499   */
500   assert(image != (const Image *) NULL);
501   assert(image->signature == MagickSignature);
502   if (image->debug != MagickFalse)
503     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
504   cube_info=GetCubeInfo();
505   if (cube_info == (CubeInfo *) NULL)
506     {
507       (void) ThrowMagickException(exception,GetMagickModule(),
508         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
509       return(cube_info);
510     }
511   GetMagickPixelPacket(image,&pixel);
512   GetMagickPixelPacket(image,&target);
513   image_view=AcquireCacheView(image);
514   for (y=0; y < (long) image->rows; y++)
515   {
516     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
517     if (p == (const PixelPacket *) NULL)
518       break;
519     indexes=GetCacheViewVirtualIndexQueue(image_view);
520     for (x=0; x < (long) image->columns; x++)
521     {
522       /*
523         Start at the root and proceed level by level.
524       */
525       node_info=cube_info->root;
526       index=MaxTreeDepth-1;
527       for (level=1; level < MaxTreeDepth; level++)
528       {
529         SetMagickPixelPacket(image,p,indexes+x,&pixel);
530         id=ColorToNodeId(image,&pixel,index);
531         if (node_info->child[id] == (NodeInfo *) NULL)
532           {
533             node_info->child[id]=GetNodeInfo(cube_info,level);
534             if (node_info->child[id] == (NodeInfo *) NULL)
535               {
536                 (void) ThrowMagickException(exception,GetMagickModule(),
537                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
538                   image->filename);
539                 return(0);
540               }
541           }
542         node_info=node_info->child[id];
543         index--;
544       }
545       for (i=0; i < (long) node_info->number_unique; i++)
546       {
547         SetMagickPixelPacket(image,&node_info->list[i].pixel,
548           &node_info->list[i].index,&target);
549         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
550           break;
551       }
552       if (i < (long) node_info->number_unique)
553         node_info->list[i].count++;
554       else
555         {
556           if (node_info->number_unique == 0)
557             node_info->list=(ColorPacket *) AcquireMagickMemory(
558               sizeof(*node_info->list));
559           else
560             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
561               (size_t) (i+1),sizeof(*node_info->list));
562           if (node_info->list == (ColorPacket *) NULL)
563             {
564               (void) ThrowMagickException(exception,GetMagickModule(),
565                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
566                 image->filename);
567               return(0);
568             }
569           node_info->list[i].pixel=(*p);
570           if ((image->colorspace == CMYKColorspace) ||
571               (image->storage_class == PseudoClass))
572             node_info->list[i].index=indexes[x];
573           node_info->list[i].count=1;
574           node_info->number_unique++;
575           cube_info->colors++;
576         }
577       p++;
578     }
579     proceed=SetImageProgress(image,EvaluateImageTag,y,image->rows);
580     if (proceed == MagickFalse)
581       break;
582   }
583   image_view=DestroyCacheView(image_view);
584   return(cube_info);
585 }
586 \f
587 /*
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589 %                                                                             %
590 %                                                                             %
591 %                                                                             %
592 +   C o n c a t e n a t e C o l o r C o m p o n e n t                         %
593 %                                                                             %
594 %                                                                             %
595 %                                                                             %
596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597 %
598 %  ConcatenateColorComponent() returns the pixel as a canonical string.
599 %
600 %  The format of the ConcatenateColorComponent() method is:
601 %
602 %      void ConcatenateColorComponent(const MagickPixelPacket *pixel,
603 %        const ChannelType channel,const ComplianceType compliance,char *tuple)
604 %
605 %  A description of each parameter follows.
606 %
607 %    o pixel:  The pixel.
608 %
609 %    channel:  The channel.
610 %
611 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
612 %
613 %    tuple:  The color tuple.
614 %
615 */
616 MagickExport void ConcatenateColorComponent(const MagickPixelPacket *pixel,
617   const ChannelType channel,const ComplianceType compliance,char *tuple)
618 {
619   char
620     component[MaxTextExtent];
621
622   MagickRealType
623     color;
624
625   color=0.0;
626   switch (channel)
627   {
628     case RedChannel:
629     {
630       color=pixel->red;
631       break;
632     }
633     case GreenChannel:
634     {
635       color=pixel->green;
636       break;
637     }
638     case BlueChannel:
639     {
640       color=pixel->blue;
641       break;
642     }
643     case AlphaChannel:
644     {
645       color=QuantumRange-pixel->opacity;
646       break;
647     }
648     case IndexChannel:
649     {
650       color=pixel->index;
651       break;
652     }
653     default:
654       break;
655   }
656   if (compliance != SVGCompliance)
657     {
658       if (pixel->depth > 16)
659         {
660           (void) FormatMagickString(component,MaxTextExtent,"%10lu",
661             (unsigned long) ScaleQuantumToLong(RoundToQuantum(color)));
662           (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
663           return;
664         }
665       if (pixel->depth > 8)
666         {
667           (void) FormatMagickString(component,MaxTextExtent,"%5d",
668             ScaleQuantumToShort(RoundToQuantum(color)));
669           (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
670           return;
671         }
672       (void) FormatMagickString(component,MaxTextExtent,"%3d",
673         ScaleQuantumToChar(RoundToQuantum(color)));
674       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
675       return;
676     }
677   if (channel == OpacityChannel)
678     {
679       (void) FormatMagickString(component,MaxTextExtent,"%g",
680         (double) (QuantumScale*color));
681       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
682       return;
683     }
684   if ((channel == RedChannel) &&
685       ((pixel->colorspace == HSBColorspace) ||
686        (pixel->colorspace == HSLColorspace) ||
687        (pixel->colorspace == HWBColorspace)))
688     {
689       (void) FormatMagickString(component,MaxTextExtent,"%g",
690         360.0*(QuantumScale*color));
691       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
692       return;
693     }
694   if (pixel->depth > 8)
695     {
696       (void) FormatMagickString(component,MaxTextExtent,"%g%%",
697         (double) (100.0*QuantumScale*color));
698       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
699       return;
700     }
701   (void) FormatMagickString(component,MaxTextExtent,"%d",
702     ScaleQuantumToChar(RoundToQuantum(color)));
703   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
704 }
705 \f
706 /*
707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 %                                                                             %
709 %                                                                             %
710 %                                                                             %
711 +   D e f i n e I m a g e H i s t o g r a m                                   %
712 %                                                                             %
713 %                                                                             %
714 %                                                                             %
715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 %
717 %  DefineImageHistogram() traverses the color cube tree and notes each colormap
718 %  entry.  A colormap entry is any node in the color cube tree where the
719 %  of unique colors is not zero.
720 %
721 %  The format of the DefineImageHistogram method is:
722 %
723 %      DefineImageHistogram(const Image *image,NodeInfo *node_info,
724 %        ColorPacket **unique_colors)
725 %
726 %  A description of each parameter follows.
727 %
728 %    o image: the image.
729 %
730 %    o node_info: the address of a structure of type NodeInfo which points to a
731 %      node in the color cube tree that is to be pruned.
732 %
733 %    o histogram: the image histogram.
734 %
735 */
736 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
737   ColorPacket **histogram)
738 {
739   register long
740     i;
741
742   unsigned long
743     number_children;
744
745   /*
746     Traverse any children.
747   */
748   number_children=image->matte == MagickFalse ? 8UL : 16UL;
749   for (i=0; i < (long) number_children; i++)
750     if (node_info->child[i] != (NodeInfo *) NULL)
751       DefineImageHistogram(image,node_info->child[i],histogram);
752   if (node_info->level == (MaxTreeDepth-1))
753     {
754       register ColorPacket
755         *p;
756
757       p=node_info->list;
758       for (i=0; i < (long) node_info->number_unique; i++)
759       {
760         (*histogram)->pixel=p->pixel;
761         (*histogram)->index=p->index;
762         (*histogram)->count=p->count;
763         (*histogram)++;
764         p++;
765       }
766     }
767 }
768 \f
769 /*
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 %                                                                             %
772 %                                                                             %
773 %                                                                             %
774 +   D e s t r o y C o l o r L i s t                                           %
775 %                                                                             %
776 %                                                                             %
777 %                                                                             %
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779 %
780 %  DestroyColorList() deallocates memory associated with the color list.
781 %
782 %  The format of the DestroyColorList method is:
783 %
784 %      DestroyColorList(void)
785 %
786 */
787
788 static void *DestroyColorElement(void *color_info)
789 {
790   register ColorInfo
791     *p;
792
793   p=(ColorInfo *) color_info;
794   if (p->path != (char *) NULL)
795     p->path=DestroyString(p->path);
796   if (p->name != (char *) NULL)
797     p->name=DestroyString(p->name);
798   p=(ColorInfo *) RelinquishMagickMemory(p);
799   return((void *) NULL);
800 }
801
802 MagickExport void DestroyColorList(void)
803 {
804   AcquireSemaphoreInfo(&color_semaphore);
805   if (color_list != (LinkedListInfo *) NULL)
806     color_list=DestroyLinkedList(color_list,DestroyColorElement);
807   instantiate_color=MagickFalse;
808   RelinquishSemaphoreInfo(color_semaphore);
809   DestroySemaphoreInfo(&color_semaphore);
810 }
811 \f
812 /*
813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814 %                                                                             %
815 %                                                                             %
816 %                                                                             %
817 +   D e s t r o y C u b e I n f o                                             %
818 %                                                                             %
819 %                                                                             %
820 %                                                                             %
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 %
823 %  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
824 %
825 %  The format of the DestroyCubeInfo method is:
826 %
827 %      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
828 %
829 %  A description of each parameter follows:
830 %
831 %    o image: the image.
832 %
833 %    o cube_info: the address of a structure of type CubeInfo.
834 %
835 */
836 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
837 {
838   register Nodes
839     *nodes;
840
841   /*
842     Release color cube tree storage.
843   */
844   DestroyColorCube(image,cube_info->root);
845   do
846   {
847     nodes=cube_info->node_queue->next;
848     cube_info->node_queue=(Nodes *)
849       RelinquishMagickMemory(cube_info->node_queue);
850     cube_info->node_queue=nodes;
851   } while (cube_info->node_queue != (Nodes *) NULL);
852   return((CubeInfo *) RelinquishMagickMemory(cube_info));
853 }
854 \f
855 /*
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857 %                                                                             %
858 %                                                                             %
859 %                                                                             %
860 +  D e s t r o y C o l o r C u b e                                            %
861 %                                                                             %
862 %                                                                             %
863 %                                                                             %
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865 %
866 %  DestroyColorCube() traverses the color cube tree and frees the list of
867 %  unique colors.
868 %
869 %  The format of the DestroyColorCube method is:
870 %
871 %      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
872 %
873 %  A description of each parameter follows.
874 %
875 %    o image: the image.
876 %
877 %    o node_info: the address of a structure of type NodeInfo which points to a
878 %      node in the color cube tree that is to be pruned.
879 %
880 */
881 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
882 {
883   register long
884     i;
885
886   unsigned long
887     number_children;
888
889   /*
890     Traverse any children.
891   */
892   number_children=image->matte == MagickFalse ? 8UL : 16UL;
893   for (i=0; i < (long) number_children; i++)
894     if (node_info->child[i] != (NodeInfo *) NULL)
895       DestroyColorCube(image,node_info->child[i]);
896   if (node_info->list != (ColorPacket *) NULL)
897     node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
898 }
899 \f
900 /*
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 %                                                                             %
903 %                                                                             %
904 %                                                                             %
905 +   G e t C o l o r I n f o                                                   %
906 %                                                                             %
907 %                                                                             %
908 %                                                                             %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 %
911 %  GetColorInfo() searches the color list for the specified name and if found
912 %  returns attributes for that color.
913 %
914 %  The format of the GetColorInfo method is:
915 %
916 %      const PixelPacket *GetColorInfo(const char *name,
917 %        ExceptionInfo *exception)
918 %
919 %  A description of each parameter follows:
920 %
921 %    o color_info: search the color list for the specified name and if found
922 %      return attributes for that color.
923 %
924 %    o name: the color name.
925 %
926 %    o exception: return any errors or warnings in this structure.
927 %
928 */
929 MagickExport const ColorInfo *GetColorInfo(const char *name,
930   ExceptionInfo *exception)
931 {
932   char
933     colorname[MaxTextExtent];
934
935   register const ColorInfo
936     *p;
937
938   register char
939     *q;
940
941   assert(exception != (ExceptionInfo *) NULL);
942   if ((color_list == (LinkedListInfo *) NULL) ||
943       (instantiate_color == MagickFalse))
944     if (InitializeColorList(exception) == MagickFalse)
945       return((const ColorInfo *) NULL);
946   if ((color_list == (LinkedListInfo *) NULL) ||
947       (IsLinkedListEmpty(color_list) != MagickFalse))
948     return((const ColorInfo *) NULL);
949   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
950     return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
951   /*
952     Strip names of whitespace.
953   */
954   (void) CopyMagickString(colorname,name,MaxTextExtent);
955   for (q=colorname; *q != '\0'; q++)
956   {
957     if (isspace((int) ((unsigned char) *q)) == 0)
958       continue;
959     (void) CopyMagickString(q,q+1,MaxTextExtent);
960     q--;
961   }
962   /*
963     Search for color tag.
964   */
965   AcquireSemaphoreInfo(&color_semaphore);
966   ResetLinkedListIterator(color_list);
967   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
968   while (p != (const ColorInfo *) NULL)
969   {
970     if (LocaleCompare(colorname,p->name) == 0)
971       break;
972     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
973   }
974   if (p == (ColorInfo *) NULL)
975     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
976       "UnrecognizedColor","`%s'",name);
977   else
978     (void) InsertValueInLinkedList(color_list,0,
979       RemoveElementByValueFromLinkedList(color_list,p));
980   RelinquishSemaphoreInfo(color_semaphore);
981   return(p);
982 }
983 \f
984 /*
985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 %                                                                             %
987 %                                                                             %
988 %                                                                             %
989 %   G e t C o l o r I n f o L i s t                                           %
990 %                                                                             %
991 %                                                                             %
992 %                                                                             %
993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994 %
995 %  GetColorInfoList() returns any colors that match the specified pattern.
996 %
997 %  The format of the GetColorInfoList function is:
998 %
999 %      const ColorInfo **GetColorInfoList(const char *pattern,
1000 %        unsigned long *number_colors,ExceptionInfo *exception)
1001 %
1002 %  A description of each parameter follows:
1003 %
1004 %    o pattern: Specifies a pointer to a text string containing a pattern.
1005 %
1006 %    o number_colors:  This integer returns the number of colors in the list.
1007 %
1008 %    o exception: return any errors or warnings in this structure.
1009 %
1010 */
1011
1012 #if defined(__cplusplus) || defined(c_plusplus)
1013 extern "C" {
1014 #endif
1015
1016 static int ColorInfoCompare(const void *x,const void *y)
1017 {
1018   const ColorInfo
1019     **p,
1020     **q;
1021
1022   p=(const ColorInfo **) x,
1023   q=(const ColorInfo **) y;
1024   if (LocaleCompare((*p)->path,(*q)->path) == 0)
1025     return(LocaleCompare((*p)->name,(*q)->name));
1026   return(LocaleCompare((*p)->path,(*q)->path));
1027 }
1028
1029 #if defined(__cplusplus) || defined(c_plusplus)
1030 }
1031 #endif
1032
1033 MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
1034   unsigned long *number_colors,ExceptionInfo *exception)
1035 {
1036   const ColorInfo
1037     **colors;
1038
1039   register const ColorInfo
1040     *p;
1041
1042   register long
1043     i;
1044
1045   /*
1046     Allocate color list.
1047   */
1048   assert(pattern != (char *) NULL);
1049   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1050   assert(number_colors != (unsigned long *) NULL);
1051   *number_colors=0;
1052   p=GetColorInfo("*",exception);
1053   if (p == (const ColorInfo *) NULL)
1054     return((const ColorInfo **) NULL);
1055   colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
1056     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1057   if (colors == (const ColorInfo **) NULL)
1058     return((const ColorInfo **) NULL);
1059   /*
1060     Generate color list.
1061   */
1062   AcquireSemaphoreInfo(&color_semaphore);
1063   ResetLinkedListIterator(color_list);
1064   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1065   for (i=0; p != (const ColorInfo *) NULL; )
1066   {
1067     if ((p->stealth == MagickFalse) &&
1068         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1069       colors[i++]=p;
1070     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1071   }
1072   RelinquishSemaphoreInfo(color_semaphore);
1073   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
1074   colors[i]=(ColorInfo *) NULL;
1075   *number_colors=(unsigned long) i;
1076   return(colors);
1077 }
1078 \f
1079 /*
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 %                                                                             %
1082 %                                                                             %
1083 %                                                                             %
1084 %   G e t C o l o r L i s t                                                   %
1085 %                                                                             %
1086 %                                                                             %
1087 %                                                                             %
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 %
1090 %  GetColorList() returns any colors that match the specified pattern.
1091 %
1092 %  The format of the GetColorList function is:
1093 %
1094 %      char **GetColorList(const char *pattern,unsigned long *number_colors,
1095 %        ExceptionInfo *exception)
1096 %
1097 %  A description of each parameter follows:
1098 %
1099 %    o pattern: Specifies a pointer to a text string containing a pattern.
1100 %
1101 %    o number_colors:  This integer returns the number of colors in the list.
1102 %
1103 %    o exception: return any errors or warnings in this structure.
1104 %
1105 */
1106
1107 #if defined(__cplusplus) || defined(c_plusplus)
1108 extern "C" {
1109 #endif
1110
1111 static int ColorCompare(const void *x,const void *y)
1112 {
1113   register const char
1114     **p,
1115     **q;
1116
1117   p=(const char **) x;
1118   q=(const char **) y;
1119   return(LocaleCompare(*p,*q));
1120 }
1121
1122 #if defined(__cplusplus) || defined(c_plusplus)
1123 }
1124 #endif
1125
1126 MagickExport char **GetColorList(const char *pattern,
1127   unsigned long *number_colors,ExceptionInfo *exception)
1128 {
1129   char
1130     **colors;
1131
1132   register const ColorInfo
1133     *p;
1134
1135   register long
1136     i;
1137
1138   /*
1139     Allocate color list.
1140   */
1141   assert(pattern != (char *) NULL);
1142   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1143   assert(number_colors != (unsigned long *) NULL);
1144   *number_colors=0;
1145   p=GetColorInfo("*",exception);
1146   if (p == (const ColorInfo *) NULL)
1147     return((char **) NULL);
1148   colors=(char **) AcquireQuantumMemory((size_t)
1149     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1150   if (colors == (char **) NULL)
1151     return((char **) NULL);
1152   /*
1153     Generate color list.
1154   */
1155   AcquireSemaphoreInfo(&color_semaphore);
1156   ResetLinkedListIterator(color_list);
1157   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1158   for (i=0; p != (const ColorInfo *) NULL; )
1159   {
1160     if ((p->stealth == MagickFalse) &&
1161         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1162       colors[i++]=ConstantString(p->name);
1163     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1164   }
1165   RelinquishSemaphoreInfo(color_semaphore);
1166   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
1167   colors[i]=(char *) NULL;
1168   *number_colors=(unsigned long) i;
1169   return(colors);
1170 }
1171 \f
1172 /*
1173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174 %                                                                             %
1175 %                                                                             %
1176 %                                                                             %
1177 +   G e t C o l o r T u p l e                                                 %
1178 %                                                                             %
1179 %                                                                             %
1180 %                                                                             %
1181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182 %
1183 %  GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
1184 %  or hex string (e.g. #FF0000).
1185 %
1186 %  The format of the GetColorTuple method is:
1187 %
1188 %      GetColorTuple(const MagickPixelPacket *pixel,const MagickBooleanType hex,
1189 %        char *tuple)
1190 %
1191 %  A description of each parameter follows.
1192 %
1193 %    o pixel: the pixel.
1194 %
1195 %    o hex: A value other than zero returns the tuple in a hexidecimal format.
1196 %
1197 %    o tuple: Return the color tuple as this string.
1198 %
1199 */
1200
1201 static void ConcatentateHexColorComponent(const MagickPixelPacket *pixel,
1202   const ChannelType channel,char *tuple)
1203 {
1204   char
1205     component[MaxTextExtent];
1206
1207   MagickRealType
1208     color;
1209
1210   color=0.0;
1211   switch (channel)
1212   {
1213     case RedChannel:
1214     {
1215       color=pixel->red;
1216       break;
1217     }
1218     case GreenChannel:
1219     {
1220       color=pixel->green;
1221       break;
1222     }
1223     case BlueChannel:
1224     {
1225       color=pixel->blue;
1226       break;
1227     }
1228     case OpacityChannel:
1229     {
1230       color=(MagickRealType) QuantumRange-pixel->opacity;
1231       break;
1232     }
1233     case IndexChannel:
1234     {
1235       color=pixel->index;
1236       break;
1237     }
1238     default:
1239       break;
1240   }
1241   if (pixel->depth > 32)
1242     {
1243       (void) FormatMagickString(component,MaxTextExtent,"%08lX",
1244         ScaleQuantumToLong(RoundToQuantum(color)));
1245       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1246       return;
1247     }
1248   if (pixel->depth > 16)
1249     {
1250       (void) FormatMagickString(component,MaxTextExtent,"%08X",
1251         (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
1252       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1253       return;
1254     }
1255   if (pixel->depth > 8)
1256     {
1257       (void) FormatMagickString(component,MaxTextExtent,"%04X",
1258         ScaleQuantumToShort(RoundToQuantum(color)));
1259       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1260       return;
1261     }
1262   (void) FormatMagickString(component,MaxTextExtent,"%02X",
1263     ScaleQuantumToChar(RoundToQuantum(color)));
1264   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1265   return;
1266 }
1267
1268 MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
1269   const MagickBooleanType hex,char *tuple)
1270 {
1271   MagickPixelPacket
1272     color;
1273
1274   assert(pixel != (const MagickPixelPacket *) NULL);
1275   assert(tuple != (char *) NULL);
1276   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
1277   *tuple='\0';
1278   if (hex != MagickFalse)
1279     {
1280       /*
1281         Convert pixel to hex color.
1282       */
1283       (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
1284       ConcatentateHexColorComponent(pixel,RedChannel,tuple);
1285       ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
1286       ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
1287       if (pixel->colorspace == CMYKColorspace)
1288         ConcatentateHexColorComponent(pixel,IndexChannel,tuple);
1289       if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
1290         ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
1291       return;
1292     }
1293   /*
1294     Convert pixel to rgb() or cmyk() color.
1295   */
1296   color=(*pixel);
1297   if (color.depth > 8)
1298     {
1299 #define SVGCompliant(component) ((MagickRealType) \
1300    ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(component))));
1301
1302       MagickStatusType
1303         status;
1304
1305       /*
1306         SVG requires color depths > 8 expressed as percentages.
1307       */
1308       status=color.red == SVGCompliant(color.red);
1309       status&=color.green == SVGCompliant(color.green);
1310       status&=color.blue == SVGCompliant(color.blue);
1311       if (color.colorspace != CMYKColorspace)
1312         status&=color.index == SVGCompliant(color.index);
1313       if (color.matte != MagickFalse)
1314         status&=color.opacity == SVGCompliant(color.opacity);
1315       if (status != MagickFalse)
1316         color.depth=8;
1317     }
1318   (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
1319     MagickColorspaceOptions,(long) color.colorspace),MaxTextExtent);
1320   if (color.matte != MagickFalse)
1321     (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
1322   (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
1323   ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
1324   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1325   ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
1326   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1327   ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
1328   if (color.colorspace == CMYKColorspace)
1329     {
1330       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1331       ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple);
1332     }
1333   if (color.matte != MagickFalse)
1334     {
1335       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1336       ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
1337     }
1338   (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1339   LocaleLower(tuple);
1340   return;
1341 }
1342 \f
1343 /*
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 %                                                                             %
1346 %                                                                             %
1347 %                                                                             %
1348 +   G e t C u b e I n f o                                                     %
1349 %                                                                             %
1350 %                                                                             %
1351 %                                                                             %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 %
1354 %  GetCubeInfo() initializes the CubeInfo data structure.
1355 %
1356 %  The format of the GetCubeInfo method is:
1357 %
1358 %      cube_info=GetCubeInfo()
1359 %
1360 %  A description of each parameter follows.
1361 %
1362 %    o cube_info: A pointer to the Cube structure.
1363 %
1364 */
1365 static CubeInfo *GetCubeInfo(void)
1366 {
1367   CubeInfo
1368     *cube_info;
1369
1370   /*
1371     Initialize tree to describe color cube.
1372   */
1373   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
1374   if (cube_info == (CubeInfo *) NULL)
1375     return((CubeInfo *) NULL);
1376   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
1377   /*
1378     Initialize root node.
1379   */
1380   cube_info->root=GetNodeInfo(cube_info,0);
1381   if (cube_info->root == (NodeInfo *) NULL)
1382     return((CubeInfo *) NULL);
1383   return(cube_info);
1384 }
1385 \f
1386 /*
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 %                                                                             %
1389 %                                                                             %
1390 %                                                                             %
1391 %  G e t I m a g e H i s t o g r a m                                          %
1392 %                                                                             %
1393 %                                                                             %
1394 %                                                                             %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 %
1397 %  GetImageHistogram() returns the unique colors in an image.
1398 %
1399 %  The format of the GetImageHistogram method is:
1400 %
1401 %      unsigned long GetImageHistogram(const Image *image,
1402 %        unsigned long *number_colors,ExceptionInfo *exception)
1403 %
1404 %  A description of each parameter follows.
1405 %
1406 %    o image: the image.
1407 %
1408 %    o file:  Write a histogram of the color distribution to this file handle.
1409 %
1410 %    o exception: return any errors or warnings in this structure.
1411 %
1412 */
1413 MagickExport ColorPacket *GetImageHistogram(const Image *image,
1414   unsigned long *number_colors,ExceptionInfo *exception)
1415 {
1416   ColorPacket
1417     *histogram;
1418
1419   CubeInfo
1420     *cube_info;
1421
1422   *number_colors=0;
1423   histogram=(ColorPacket *) NULL;
1424   cube_info=ClassifyImageColors(image,exception);
1425   if (cube_info != (CubeInfo *) NULL)
1426     {
1427       histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
1428         sizeof(*histogram));
1429       if (histogram == (ColorPacket *) NULL)
1430         (void) ThrowMagickException(exception,GetMagickModule(),
1431           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1432       else
1433         {
1434           ColorPacket
1435             *root;
1436
1437           *number_colors=cube_info->colors;
1438           root=histogram;
1439           DefineImageHistogram(image,cube_info->root,&root);
1440         }
1441     }
1442   cube_info=DestroyCubeInfo(image,cube_info);
1443   return(histogram);
1444 }
1445 \f
1446 /*
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 %                                                                             %
1449 %                                                                             %
1450 %                                                                             %
1451 +  G e t N o d e I n f o                                                      %
1452 %                                                                             %
1453 %                                                                             %
1454 %                                                                             %
1455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1456 %
1457 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
1458 %  presets all fields to zero.
1459 %
1460 %  The format of the GetNodeInfo method is:
1461 %
1462 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1463 %
1464 %  A description of each parameter follows.
1465 %
1466 %    o cube_info: A pointer to the CubeInfo structure.
1467 %
1468 %    o level: Specifies the level in the storage_class the node resides.
1469 %
1470 */
1471 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1472 {
1473   NodeInfo
1474     *node_info;
1475
1476   if (cube_info->free_nodes == 0)
1477     {
1478       Nodes
1479         *nodes;
1480
1481       /*
1482         Allocate a new nodes of nodes.
1483       */
1484       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
1485       if (nodes == (Nodes *) NULL)
1486         return((NodeInfo *) NULL);
1487       nodes->next=cube_info->node_queue;
1488       cube_info->node_queue=nodes;
1489       cube_info->node_info=nodes->nodes;
1490       cube_info->free_nodes=NodesInAList;
1491     }
1492   cube_info->free_nodes--;
1493   node_info=cube_info->node_info++;
1494   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
1495   node_info->level=level;
1496   return(node_info);
1497 }
1498 \f
1499 /*
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501 %                                                                             %
1502 %                                                                             %
1503 %                                                                             %
1504 %  G e t N u m b e r C o l o r s                                              %
1505 %                                                                             %
1506 %                                                                             %
1507 %                                                                             %
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1509 %
1510 %  GetNumberColors() returns the number of unique colors in an image.
1511 %
1512 %  The format of the GetNumberColors method is:
1513 %
1514 %      unsigned long GetNumberColors(const Image *image,FILE *file,
1515 %        ExceptionInfo *exception)
1516 %
1517 %  A description of each parameter follows.
1518 %
1519 %    o image: the image.
1520 %
1521 %    o file:  Write a histogram of the color distribution to this file handle.
1522 %
1523 %    o exception: return any errors or warnings in this structure.
1524 %
1525 */
1526
1527 #if defined(__cplusplus) || defined(c_plusplus)
1528 extern "C" {
1529 #endif
1530
1531 static int HistogramCompare(const void *x,const void *y)
1532 {
1533   const ColorPacket
1534     *color_1,
1535     *color_2;
1536
1537   color_1=(const ColorPacket *) x;
1538   color_2=(const ColorPacket *) y;
1539   if (color_2->pixel.red != color_1->pixel.red)
1540     return((int) color_1->pixel.red-(int) color_2->pixel.red);
1541   if (color_2->pixel.green != color_1->pixel.green)
1542     return((int) color_1->pixel.green-(int) color_2->pixel.green);
1543   if (color_2->pixel.blue != color_1->pixel.blue)
1544     return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
1545   return((int) color_2->count-(int) color_1->count);
1546 }
1547
1548 #if defined(__cplusplus) || defined(c_plusplus)
1549 }
1550 #endif
1551
1552 MagickExport unsigned long GetNumberColors(const Image *image,FILE *file,
1553   ExceptionInfo *exception)
1554 {
1555 #define HistogramImageTag  "Histogram/Image"
1556
1557   char
1558     color[MaxTextExtent],
1559     hex[MaxTextExtent],
1560     tuple[MaxTextExtent];
1561
1562   ColorPacket
1563     *histogram;
1564
1565   MagickPixelPacket
1566     pixel;
1567
1568   register ColorPacket
1569     *p;
1570
1571   register long
1572     i;
1573
1574   unsigned long
1575     number_colors;
1576
1577   number_colors=0;
1578   if (file == (FILE *) NULL)
1579     {
1580       CubeInfo
1581         *cube_info;
1582
1583       cube_info=ClassifyImageColors(image,exception);
1584       if (cube_info != (CubeInfo *) NULL)
1585         number_colors=cube_info->colors;
1586       cube_info=DestroyCubeInfo(image,cube_info);
1587       return(number_colors);
1588     }
1589   histogram=GetImageHistogram(image,&number_colors,exception);
1590   if (histogram == (ColorPacket *) NULL)
1591     return(number_colors);
1592   qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1593     HistogramCompare);
1594   GetMagickPixelPacket(image,&pixel);
1595   p=histogram;
1596   for (i=0; i < (long) number_colors; i++)
1597   {
1598     SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel);
1599     (void) CopyMagickString(tuple,"(",MaxTextExtent);
1600     ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1601     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1602     ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1603     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1604     ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1605     if (pixel.colorspace == CMYKColorspace)
1606       {
1607         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1608         ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
1609       }
1610     if (pixel.matte != MagickFalse)
1611       {
1612         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1613         ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
1614       }
1615     (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1616     (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
1617     GetColorTuple(&pixel,MagickTrue,hex);
1618     (void) fprintf(file,MagickSizeFormat,p->count);
1619     (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
1620     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1621         (QuantumTick(i,number_colors) != MagickFalse))
1622       (void) image->progress_monitor(HistogramImageTag,i,number_colors,
1623         image->client_data);
1624     p++;
1625   }
1626   (void) fflush(file);
1627   histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
1628   return(number_colors);
1629 }
1630 \f
1631 /*
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %                                                                             %
1634 %                                                                             %
1635 %                                                                             %
1636 +   I n i t i a l i z e C o l o r L i s t                                     %
1637 %                                                                             %
1638 %                                                                             %
1639 %                                                                             %
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 %
1642 %  InitializeColorList() initializes the color list.
1643 %
1644 %  The format of the InitializeColorList method is:
1645 %
1646 %      MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1647 %
1648 %  A description of each parameter follows.
1649 %
1650 %    o exception: return any errors or warnings in this structure.
1651 %
1652 */
1653 static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1654 {
1655   if ((color_list == (LinkedListInfo *) NULL) &&
1656       (instantiate_color == MagickFalse))
1657     {
1658       AcquireSemaphoreInfo(&color_semaphore);
1659       if ((color_list == (LinkedListInfo *) NULL) &&
1660           (instantiate_color == MagickFalse))
1661         {
1662           (void) LoadColorLists(ColorFilename,exception);
1663           instantiate_color=MagickTrue;
1664         }
1665       RelinquishSemaphoreInfo(color_semaphore);
1666     }
1667   return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1668 }
1669 \f
1670 /*
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 %                                                                             %
1673 %                                                                             %
1674 %                                                                             %
1675 +   I s C o l o r S i m i l a r                                               %
1676 %                                                                             %
1677 %                                                                             %
1678 %                                                                             %
1679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 %
1681 %  IsColorSimilar() returns MagickTrue if the distance between two colors is
1682 %  less than the specified distance in a linear three dimensional color space.
1683 %  This method is used by ColorFloodFill() and other algorithms which
1684 %  compare two colors.
1685 %
1686 %  The format of the IsColorSimilar method is:
1687 %
1688 %      void IsColorSimilar(const Image *image,const PixelPacket *p,
1689 %        const PixelPacket *q)
1690 %
1691 %  A description of each parameter follows:
1692 %
1693 %    o image: the image.
1694 %
1695 %    o p: Pixel p.
1696 %
1697 %    o q: Pixel q.
1698 %
1699 */
1700
1701 static inline double MagickMax(const double x,const double y)
1702 {
1703   if (x > y)
1704     return(x);
1705   return(y);
1706 }
1707
1708 MagickExport MagickBooleanType IsColorSimilar(const Image *image,
1709   const PixelPacket *p,const PixelPacket *q)
1710 {
1711   MagickRealType
1712     fuzz,
1713     pixel;
1714
1715   register MagickRealType
1716     alpha,
1717     beta,
1718     distance;
1719
1720   if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
1721     return(IsColorEqual(p,q));
1722   fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
1723     MagickSQ1_2);
1724   alpha=1.0;
1725   beta=1.0;
1726   if (image->matte != MagickFalse)
1727     {
1728       alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1729       beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1730     }
1731   pixel=alpha*p->red-beta*q->red;
1732   distance=pixel*pixel;
1733   if (distance > fuzz)
1734     return(MagickFalse);
1735   pixel=alpha*p->green-beta*q->green;
1736   distance+=pixel*pixel;
1737   if (distance > fuzz)
1738     return(MagickFalse);
1739   pixel=alpha*p->blue-beta*q->blue;
1740   distance+=pixel*pixel;
1741   if (distance > fuzz)
1742     return(MagickFalse);
1743   return(MagickTrue);
1744 }
1745 \f
1746 /*
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 %                                                                             %
1749 %                                                                             %
1750 %                                                                             %
1751 %     I s G r a y I m a g e                                                   %
1752 %                                                                             %
1753 %                                                                             %
1754 %                                                                             %
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756 %
1757 %  IsGrayImage() returns MagickTrue if all the pixels in the image have the
1758 %  same red, green, and blue intensities.
1759 %
1760 %  The format of the IsGrayImage method is:
1761 %
1762 %      MagickBooleanType IsGrayImage(const Image *image,
1763 %        ExceptionInfo *exception)
1764 %
1765 %  A description of each parameter follows:
1766 %
1767 %    o image: the image.
1768 %
1769 %    o exception: return any errors or warnings in this structure.
1770 %
1771 */
1772 MagickExport MagickBooleanType IsGrayImage(const Image *image,
1773   ExceptionInfo *exception)
1774 {
1775   ImageType
1776     type;
1777
1778   register const PixelPacket
1779     *p;
1780
1781   assert(image != (Image *) NULL);
1782   assert(image->signature == MagickSignature);
1783   if (image->debug != MagickFalse)
1784     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1785   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1786       (image->type == GrayscaleMatteType))
1787     return(MagickTrue);
1788   if (image->colorspace == CMYKColorspace)
1789     return(MagickFalse);
1790   type=BilevelType;
1791   switch (image->storage_class)
1792   {
1793     case DirectClass:
1794     case UndefinedClass:
1795     {
1796       long
1797         y;
1798
1799       register long
1800         x;
1801
1802       CacheView
1803         *image_view;
1804
1805       image_view=AcquireCacheView(image);
1806       for (y=0; y < (long) image->rows; y++)
1807       {
1808         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1809         if (p == (const PixelPacket *) NULL)
1810           break;
1811         for (x=0; x < (long) image->columns; x++)
1812         {
1813           if (IsGrayPixel(p) == MagickFalse)
1814             {
1815               type=UndefinedType;
1816               break;
1817             }
1818           if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1819             type=GrayscaleType;
1820           p++;
1821         }
1822         if (type == UndefinedType)
1823           break;
1824       }
1825       image_view=DestroyCacheView(image_view);
1826       break;
1827     }
1828     case PseudoClass:
1829     {
1830       register long
1831         i;
1832
1833       p=image->colormap;
1834       for (i=0; i < (long) image->colors; i++)
1835       {
1836         if (IsGrayPixel(p) == MagickFalse)
1837           {
1838             type=UndefinedType;
1839             break;
1840           }
1841         if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1842           type=GrayscaleType;
1843         p++;
1844       }
1845       break;
1846     }
1847   }
1848   if (type == UndefinedType)
1849     return(MagickFalse);
1850   ((Image *) image)->type=type;
1851   if ((type == GrayscaleType) && (image->matte != MagickFalse))
1852     ((Image *) image)->type=GrayscaleMatteType;
1853   return(MagickTrue);
1854 }
1855 \f
1856 /*
1857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858 %                                                                             %
1859 %                                                                             %
1860 %                                                                             %
1861 %  I s H i s t o g r a m I m a g e                                            %
1862 %                                                                             %
1863 %                                                                             %
1864 %                                                                             %
1865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1866 %
1867 %  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
1868 %  less.
1869 %
1870 %  The format of the IsHistogramImage method is:
1871 %
1872 %      MagickBooleanType IsHistogramImage(const Image *image,
1873 %        ExceptionInfo *exception)
1874 %
1875 %  A description of each parameter follows.
1876 %
1877 %    o image: the image.
1878 %
1879 %    o exception: return any errors or warnings in this structure.
1880 %
1881 */
1882 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
1883   ExceptionInfo *exception)
1884 {
1885 #define MaximumUniqueColors  1024
1886
1887   CubeInfo
1888     *cube_info;
1889
1890   long
1891     y;
1892
1893   MagickPixelPacket
1894     pixel,
1895     target;
1896
1897   register const IndexPacket
1898     *indexes;
1899
1900   register const PixelPacket
1901     *p;
1902
1903   register long
1904     x;
1905
1906   register NodeInfo
1907     *node_info;
1908
1909   register long
1910     i;
1911
1912   unsigned long
1913     id,
1914     index,
1915     level;
1916
1917   CacheView
1918     *image_view;
1919
1920   assert(image != (Image *) NULL);
1921   assert(image->signature == MagickSignature);
1922   if (image->debug != MagickFalse)
1923     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1924   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1925     return(MagickTrue);
1926   if (image->storage_class == PseudoClass)
1927     return(MagickFalse);
1928   /*
1929     Initialize color description tree.
1930   */
1931   cube_info=GetCubeInfo();
1932   if (cube_info == (CubeInfo *) NULL)
1933     {
1934       (void) ThrowMagickException(exception,GetMagickModule(),
1935         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1936       return(MagickFalse);
1937     }
1938   GetMagickPixelPacket(image,&pixel);
1939   GetMagickPixelPacket(image,&target);
1940   image_view=AcquireCacheView(image);
1941   for (y=0; y < (long) image->rows; y++)
1942   {
1943     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1944     if (p == (const PixelPacket *) NULL)
1945       break;
1946     indexes=GetCacheViewVirtualIndexQueue(image_view);
1947     for (x=0; x < (long) image->columns; x++)
1948     {
1949       /*
1950         Start at the root and proceed level by level.
1951       */
1952       node_info=cube_info->root;
1953       index=MaxTreeDepth-1;
1954       for (level=1; level < MaxTreeDepth; level++)
1955       {
1956         SetMagickPixelPacket(image,p,indexes+x,&pixel);
1957         id=ColorToNodeId(image,&pixel,index);
1958         if (node_info->child[id] == (NodeInfo *) NULL)
1959           {
1960             node_info->child[id]=GetNodeInfo(cube_info,level);
1961             if (node_info->child[id] == (NodeInfo *) NULL)
1962               {
1963                 (void) ThrowMagickException(exception,GetMagickModule(),
1964                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
1965                   image->filename);
1966                 break;
1967               }
1968           }
1969         node_info=node_info->child[id];
1970         index--;
1971       }
1972       if (level < MaxTreeDepth)
1973         break;
1974       for (i=0; i < (long) node_info->number_unique; i++)
1975       {
1976         SetMagickPixelPacket(image,&node_info->list[i].pixel,
1977           &node_info->list[i].index,&target);
1978         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
1979           break;
1980       }
1981       if (i < (long) node_info->number_unique)
1982         node_info->list[i].count++;
1983       else
1984         {
1985           /*
1986             Add this unique color to the color list.
1987           */
1988           if (node_info->number_unique == 0)
1989             node_info->list=(ColorPacket *) AcquireMagickMemory(
1990               sizeof(*node_info->list));
1991           else
1992             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
1993               (size_t) (i+1),sizeof(*node_info->list));
1994           if (node_info->list == (ColorPacket *) NULL)
1995             {
1996               (void) ThrowMagickException(exception,GetMagickModule(),
1997                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1998                 image->filename);
1999               break;
2000             }
2001           node_info->list[i].pixel=(*p);
2002           if ((image->colorspace == CMYKColorspace) ||
2003               (image->storage_class == PseudoClass))
2004             node_info->list[i].index=indexes[x];
2005           node_info->list[i].count=1;
2006           node_info->number_unique++;
2007           cube_info->colors++;
2008           if (cube_info->colors > MaximumUniqueColors)
2009             break;
2010         }
2011       p++;
2012     }
2013     if (x < (long) image->columns)
2014       break;
2015   }
2016   image_view=DestroyCacheView(image_view);
2017   cube_info=DestroyCubeInfo(image,cube_info);
2018   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2019 }
2020 \f
2021 /*
2022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023 %                                                                             %
2024 %                                                                             %
2025 %                                                                             %
2026 +   I s I m a g e S i m i l a r                                               %
2027 %                                                                             %
2028 %                                                                             %
2029 %                                                                             %
2030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2031 %
2032 %  IsImageSimilar() returns true if the target is similar to a region of the
2033 %  image.
2034 %
2035 %  The format of the IsImageSimilar method is:
2036 %
2037 %      MagickBooleanType IsImageSimilar(const Image *image,
2038 %        const Image *target_image,long *x_offset,long *y_offset,
2039 %        ExceptionInfo *exception)
2040 %
2041 %  A description of each parameter follows:
2042 %
2043 %    o image: the image.
2044 %
2045 %    o target_image: the target image.
2046 %
2047 %    o x_offset: On input the starting x position to search for a match;
2048 %      on output the x position of the first match found.
2049 %
2050 %    o y_offset: On input the starting y position to search for a match;
2051 %      on output the y position of the first match found.
2052 %
2053 %    o exception: return any errors or warnings in this structure.
2054 %
2055 */
2056 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
2057   const Image *target_image,long *x_offset,long *y_offset,
2058   ExceptionInfo *exception)
2059 {
2060 #define SearchImageText  "  Searching image...  "
2061
2062   long
2063     j,
2064     y;
2065
2066   MagickBooleanType
2067     status;
2068
2069   MagickPixelPacket
2070     target,
2071     pixel;
2072
2073   register const PixelPacket
2074     *p,
2075     *q;
2076
2077   register const IndexPacket
2078     *indexes,
2079     *target_indexes;
2080
2081   register long
2082     i,
2083     x;
2084
2085   CacheView
2086     *image_view,
2087     *target_view;
2088
2089   assert(image != (Image *) NULL);
2090   assert(image->signature == MagickSignature);
2091   if (image->debug != MagickFalse)
2092     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2093   assert(target_image != (Image *) NULL);
2094   assert(target_image->signature == MagickSignature);
2095   assert(x_offset != (long *) NULL);
2096   assert(y_offset != (long *) NULL);
2097   assert(exception != (ExceptionInfo *) NULL);
2098   x=0;
2099   GetMagickPixelPacket(image,&pixel);
2100   GetMagickPixelPacket(image,&target);
2101   image_view=AcquireCacheView(image);
2102   target_view=AcquireCacheView(target_image);
2103   for (y=(*y_offset); y < (long) image->rows; y++)
2104   {
2105     for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
2106     {
2107       for (j=0; j < (long) target_image->rows; j++)
2108       {
2109         for (i=0; i < (long) target_image->columns; i++)
2110         {
2111           p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
2112           indexes=GetCacheViewVirtualIndexQueue(image_view);
2113           SetMagickPixelPacket(image,p,indexes,&pixel);
2114           q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
2115           target_indexes=GetCacheViewVirtualIndexQueue(target_view);
2116           SetMagickPixelPacket(image,q,target_indexes,&target);
2117           if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
2118             break;
2119         }
2120         if (i < (long) target_image->columns)
2121           break;
2122       }
2123       if (j == (long) target_image->rows)
2124         break;
2125     }
2126     if (x < (long) image->columns)
2127       break;
2128     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
2129         (QuantumTick(y,image->rows) != MagickFalse))
2130       {
2131         status=image->progress_monitor(SearchImageText,y,image->rows,
2132           image->client_data);
2133         if (status == MagickFalse)
2134           break;
2135       }
2136   }
2137   target_view=DestroyCacheView(target_view);
2138   image_view=DestroyCacheView(image_view);
2139   *x_offset=x;
2140   *y_offset=y;
2141   return(y < (long) image->rows ? MagickTrue : MagickFalse);
2142 }
2143 \f
2144 /*
2145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2146 %                                                                             %
2147 %                                                                             %
2148 %                                                                             %
2149 +   I s M a g i c k C o l o r S i m i l a r                                   %
2150 %                                                                             %
2151 %                                                                             %
2152 %                                                                             %
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2154 %
2155 %  IsMagickColorSimilar() returns true if the distance between two colors is
2156 %  less than the specified distance in a linear three dimensional color space.
2157 %  This method is used by ColorFloodFill() and other algorithms which
2158 %  compare two colors.
2159 %
2160 %  The format of the IsMagickColorSimilar method is:
2161 %
2162 %      MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2163 %        const MagickPixelPacket *q)
2164 %
2165 %  A description of each parameter follows:
2166 %
2167 %    o p: Pixel p.
2168 %
2169 %    o q: Pixel q.
2170 %
2171 */
2172 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2173   const MagickPixelPacket *q)
2174 {
2175   MagickRealType
2176     fuzz,
2177     pixel;
2178
2179   register MagickRealType
2180     alpha,
2181     beta,
2182     distance;
2183
2184   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
2185     return(IsMagickColorEqual(p,q));
2186   if (p->fuzz == 0.0)
2187     fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2188   else
2189     if (q->fuzz == 0.0)
2190       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
2191     else
2192       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2193   alpha=1.0;
2194   if (p->matte != MagickFalse)
2195     alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
2196   beta=1.0;
2197   if (q->matte != MagickFalse)
2198     beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
2199   if (p->colorspace == CMYKColorspace)
2200     {
2201       alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
2202       beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
2203     }
2204   pixel=alpha*p->red-beta*q->red;
2205   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
2206       (p->colorspace == HWBColorspace))
2207     {
2208       if (fabs(p->red-q->red) > (QuantumRange/2))
2209         {
2210           if (p->red > (QuantumRange/2))
2211             pixel=alpha*(p->red-QuantumRange)-beta*q->red;
2212           else
2213             pixel=alpha*p->red-beta*(q->red-QuantumRange);
2214         }
2215         pixel*=2;
2216      }
2217   distance=pixel*pixel;
2218   if (distance > fuzz)
2219     return(MagickFalse);
2220   pixel=alpha*p->green-beta*q->green;
2221   distance+=pixel*pixel;
2222   if (distance > fuzz)
2223     return(MagickFalse);
2224   pixel=alpha*p->blue-beta*q->blue;
2225   distance+=pixel*pixel;
2226   if (distance > fuzz)
2227     return(MagickFalse);
2228   pixel=p->opacity-q->opacity;
2229   distance+=pixel*pixel;
2230   if (distance > fuzz)
2231     return(MagickFalse);
2232   return(MagickTrue);
2233 }
2234 \f
2235 /*
2236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 %                                                                             %
2238 %                                                                             %
2239 %                                                                             %
2240 %   I s M o n o c h r o m e I m a g e                                         %
2241 %                                                                             %
2242 %                                                                             %
2243 %                                                                             %
2244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2245 %
2246 %  IsMonochromeImage() returns MagickTrue if all the pixels in the image have
2247 %  the same red, green, and blue intensities and the intensity is either
2248 %  0 or QuantumRange.
2249 %
2250 %  The format of the IsMonochromeImage method is:
2251 %
2252 %      MagickBooleanType IsMonochromeImage(const Image *image,
2253 %        ExceptionInfo *exception)
2254 %
2255 %  A description of each parameter follows:
2256 %
2257 %    o image: the image.
2258 %
2259 %    o exception: return any errors or warnings in this structure.
2260 %
2261 */
2262 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
2263   ExceptionInfo *exception)
2264 {
2265   ImageType
2266     type;
2267
2268   register const PixelPacket
2269     *p;
2270
2271   assert(image != (Image *) NULL);
2272   assert(image->signature == MagickSignature);
2273   if (image->debug != MagickFalse)
2274     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2275   if (image->type == BilevelType)
2276     return(MagickTrue);
2277   if (image->colorspace == CMYKColorspace)
2278     return(MagickFalse);
2279   type=BilevelType;
2280   switch (image->storage_class)
2281   {
2282     case DirectClass:
2283     case UndefinedClass:
2284     {
2285       long
2286         y;
2287
2288       register long
2289         x;
2290
2291       CacheView
2292         *image_view;
2293
2294       image_view=AcquireCacheView(image);
2295       for (y=0; y < (long) image->rows; y++)
2296       {
2297         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2298         if (p == (const PixelPacket *) NULL)
2299           break;
2300         for (x=0; x < (long) image->columns; x++)
2301         {
2302           if (IsMonochromePixel(p) == MagickFalse)
2303             {
2304               type=UndefinedType;
2305               break;
2306             }
2307           p++;
2308         }
2309         if (type == UndefinedType)
2310           break;
2311       }
2312       image_view=DestroyCacheView(image_view);
2313       if (y == (long) image->rows)
2314         ((Image *) image)->type=BilevelType;
2315       break;
2316     }
2317     case PseudoClass:
2318     {
2319       register long
2320         i;
2321
2322       p=image->colormap;
2323       for (i=0; i < (long) image->colors; i++)
2324       {
2325         if (IsMonochromePixel(p) == MagickFalse)
2326           {
2327             type=UndefinedType;
2328             break;
2329           }
2330         p++;
2331       }
2332       break;
2333     }
2334   }
2335   if (type == UndefinedType)
2336     return(MagickFalse);
2337   ((Image *) image)->type=type;
2338   return(MagickTrue);
2339 }
2340 \f
2341 /*
2342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 %                                                                             %
2344 %                                                                             %
2345 %                                                                             %
2346 +   I s O p a c i t y S i m i l a r                                           %
2347 %                                                                             %
2348 %                                                                             %
2349 %                                                                             %
2350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351 %
2352 %  IsOpacitySimilar() returns true if the distance between two opacity
2353 %  values is less than the specified distance in a linear color space.  This
2354 %  method is used by MatteFloodFill() and other algorithms which compare
2355 %  two opacity values.
2356 %
2357 %  The format of the IsOpacitySimilar method is:
2358 %
2359 %      void IsOpacitySimilar(const Image *image,const PixelPacket *p,
2360 %        const PixelPacket *q)
2361 %
2362 %  A description of each parameter follows:
2363 %
2364 %    o image: the image.
2365 %
2366 %    o p: Pixel p.
2367 %
2368 %    o q: Pixel q.
2369 %
2370 */
2371 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
2372   const PixelPacket *p,const PixelPacket *q)
2373 {
2374   MagickRealType
2375     fuzz,
2376     pixel;
2377
2378   register MagickRealType
2379     distance;
2380
2381   if (image->matte == MagickFalse)
2382     return(MagickTrue);
2383   if (p->opacity == q->opacity)
2384     return(MagickTrue);
2385   fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
2386   pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
2387   distance=pixel*pixel;
2388   if (distance > fuzz)
2389     return(MagickFalse);
2390   return(MagickTrue);
2391 }
2392 \f
2393 /*
2394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395 %                                                                             %
2396 %                                                                             %
2397 %                                                                             %
2398 %     I s O p a q u e I m a g e                                               %
2399 %                                                                             %
2400 %                                                                             %
2401 %                                                                             %
2402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403 %
2404 %  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
2405 %  an opacity value other than opaque (0).
2406 %
2407 %  The format of the IsOpaqueImage method is:
2408 %
2409 %      MagickBooleanType IsOpaqueImage(const Image *image,
2410 %        ExceptionInfo *exception)
2411 %
2412 %  A description of each parameter follows:
2413 %
2414 %    o image: the image.
2415 %
2416 %    o exception: return any errors or warnings in this structure.
2417 %
2418 */
2419 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
2420   ExceptionInfo *exception)
2421 {
2422   long
2423     y;
2424
2425   register const PixelPacket
2426     *p;
2427
2428   register long
2429     x;
2430
2431   CacheView
2432     *image_view;
2433
2434   /*
2435     Determine if image is opaque.
2436   */
2437   assert(image != (Image *) NULL);
2438   assert(image->signature == MagickSignature);
2439   if (image->debug != MagickFalse)
2440     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2441   if (image->matte == MagickFalse)
2442     return(MagickTrue);
2443   image_view=AcquireCacheView(image);
2444   for (y=0; y < (long) image->rows; y++)
2445   {
2446     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2447     if (p == (const PixelPacket *) NULL)
2448       break;
2449     for (x=0; x < (long) image->columns; x++)
2450     {
2451       if (p->opacity != OpaqueOpacity)
2452         break;
2453       p++;
2454     }
2455     if (x < (long) image->columns)
2456      break;
2457   }
2458   image_view=DestroyCacheView(image_view);
2459   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2460 }
2461 \f
2462 /*
2463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464 %                                                                             %
2465 %                                                                             %
2466 %                                                                             %
2467 %  I s P a l e t t e I m a g e                                                %
2468 %                                                                             %
2469 %                                                                             %
2470 %                                                                             %
2471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472 %
2473 %  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
2474 %  unique colors or less.
2475 %
2476 %  The format of the IsPaletteImage method is:
2477 %
2478 %      MagickBooleanType IsPaletteImage(const Image *image,
2479 %        ExceptionInfo *exception)
2480 %
2481 %  A description of each parameter follows.
2482 %
2483 %    o image: the image.
2484 %
2485 %    o exception: return any errors or warnings in this structure.
2486 %
2487 */
2488 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
2489   ExceptionInfo *exception)
2490 {
2491   CubeInfo
2492     *cube_info;
2493
2494   long
2495     y;
2496
2497   MagickPixelPacket
2498     pixel,
2499     target;
2500
2501   register const IndexPacket
2502     *indexes;
2503
2504   register const PixelPacket
2505     *p;
2506
2507   register long
2508     x;
2509
2510   register NodeInfo
2511     *node_info;
2512
2513   register long
2514     i;
2515
2516   unsigned long
2517     id,
2518     index,
2519     level;
2520
2521   CacheView
2522     *image_view;
2523
2524   assert(image != (Image *) NULL);
2525   assert(image->signature == MagickSignature);
2526   if (image->debug != MagickFalse)
2527     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2528   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
2529     return(MagickTrue);
2530   if (image->storage_class == PseudoClass)
2531     return(MagickFalse);
2532   /*
2533     Initialize color description tree.
2534   */
2535   cube_info=GetCubeInfo();
2536   if (cube_info == (CubeInfo *) NULL)
2537     {
2538       (void) ThrowMagickException(exception,GetMagickModule(),
2539         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2540       return(MagickFalse);
2541     }
2542   GetMagickPixelPacket(image,&pixel);
2543   GetMagickPixelPacket(image,&target);
2544   image_view=AcquireCacheView(image);
2545   for (y=0; y < (long) image->rows; y++)
2546   {
2547     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2548     if (p == (const PixelPacket *) NULL)
2549       break;
2550     indexes=GetCacheViewVirtualIndexQueue(image_view);
2551     for (x=0; x < (long) image->columns; x++)
2552     {
2553       /*
2554         Start at the root and proceed level by level.
2555       */
2556       node_info=cube_info->root;
2557       index=MaxTreeDepth-1;
2558       for (level=1; level < MaxTreeDepth; level++)
2559       {
2560         SetMagickPixelPacket(image,p,indexes+x,&pixel);
2561         id=ColorToNodeId(image,&pixel,index);
2562         if (node_info->child[id] == (NodeInfo *) NULL)
2563           {
2564             node_info->child[id]=GetNodeInfo(cube_info,level);
2565             if (node_info->child[id] == (NodeInfo *) NULL)
2566               {
2567                 (void) ThrowMagickException(exception,GetMagickModule(),
2568                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
2569                   image->filename);
2570                 break;
2571               }
2572           }
2573         node_info=node_info->child[id];
2574         index--;
2575       }
2576       if (level < MaxTreeDepth)
2577         break;
2578       for (i=0; i < (long) node_info->number_unique; i++)
2579       {
2580         SetMagickPixelPacket(image,&node_info->list[i].pixel,
2581           &node_info->list[i].index,&target);
2582         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
2583           break;
2584       }
2585       if (i < (long) node_info->number_unique)
2586         node_info->list[i].count++;
2587       else
2588         {
2589           /*
2590             Add this unique color to the color list.
2591           */
2592           if (node_info->number_unique == 0)
2593             node_info->list=(ColorPacket *) AcquireMagickMemory(
2594               sizeof(*node_info->list));
2595           else
2596             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
2597               (size_t) (i+1),sizeof(*node_info->list));
2598           if (node_info->list == (ColorPacket *) NULL)
2599             {
2600               (void) ThrowMagickException(exception,GetMagickModule(),
2601                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2602                 image->filename);
2603               break;
2604             }
2605           node_info->list[i].pixel=(*p);
2606           if ((image->colorspace == CMYKColorspace) ||
2607               (image->storage_class == PseudoClass))
2608             node_info->list[i].index=indexes[x];
2609           node_info->list[i].count=1;
2610           node_info->number_unique++;
2611           cube_info->colors++;
2612           if (cube_info->colors > 256)
2613             break;
2614         }
2615       p++;
2616     }
2617     if (x < (long) image->columns)
2618       break;
2619   }
2620   image_view=DestroyCacheView(image_view);
2621   cube_info=DestroyCubeInfo(image,cube_info);
2622   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2623 }
2624 \f
2625 /*
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627 %                                                                             %
2628 %                                                                             %
2629 %                                                                             %
2630 %  L i s t C o l o r I n f o                                                  %
2631 %                                                                             %
2632 %                                                                             %
2633 %                                                                             %
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635 %
2636 %  ListColorInfo() lists color names to the specified file.  Color names
2637 %  are a convenience.  Rather than defining a color by its red, green, and
2638 %  blue intensities just use a color name such as white, blue, or yellow.
2639 %
2640 %  The format of the ListColorInfo method is:
2641 %
2642 %      MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
2643 %
2644 %  A description of each parameter follows.
2645 %
2646 %    o file:  List color names to this file handle.
2647 %
2648 %    o exception: return any errors or warnings in this structure.
2649 %
2650 */
2651 MagickExport MagickBooleanType ListColorInfo(FILE *file,
2652   ExceptionInfo *exception)
2653 {
2654   char
2655     tuple[MaxTextExtent];
2656
2657   const char
2658     *path;
2659
2660   const ColorInfo
2661     **color_info;
2662
2663   register long
2664     i;
2665
2666   unsigned long
2667     number_colors;
2668
2669   /*
2670     List name and attributes of each color in the list.
2671   */
2672   if (file == (const FILE *) NULL)
2673     file=stdout;
2674   color_info=GetColorInfoList("*",&number_colors,exception);
2675   if (color_info == (const ColorInfo **) NULL)
2676     return(MagickFalse);
2677   path=(const char *) NULL;
2678   for (i=0; i < (long) number_colors; i++)
2679   {
2680     if (color_info[i]->stealth != MagickFalse)
2681       continue;
2682     if ((path == (const char *) NULL) ||
2683         (LocaleCompare(path,color_info[i]->path) != 0))
2684       {
2685         if (color_info[i]->path != (char *) NULL)
2686           (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
2687         (void) fprintf(file,"Name                  Color                  "
2688           "                       Compliance\n");
2689         (void) fprintf(file,"-------------------------------------------------"
2690           "------------------------------\n");
2691       }
2692     path=color_info[i]->path;
2693     (void) fprintf(file,"%-21.21s ",color_info[i]->name);
2694     GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
2695     (void) fprintf(file,"%-45.45s ",tuple);
2696     if ((color_info[i]->compliance & SVGCompliance) != 0)
2697       (void) fprintf(file,"SVG ");
2698     if ((color_info[i]->compliance & X11Compliance) != 0)
2699       (void) fprintf(file,"X11 ");
2700     if ((color_info[i]->compliance & XPMCompliance) != 0)
2701       (void) fprintf(file,"XPM ");
2702     (void) fprintf(file,"\n");
2703   }
2704   color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
2705   (void) fflush(file);
2706   return(MagickTrue);
2707 }
2708 \f
2709 /*
2710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711 %                                                                             %
2712 %                                                                             %
2713 %                                                                             %
2714 +   L o a d C o l o r L i s t                                                 %
2715 %                                                                             %
2716 %                                                                             %
2717 %                                                                             %
2718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719 %
2720 %  LoadColorList() loads the color configuration file which provides a mapping
2721 %  between color attributes and a color name.
2722 %
2723 %  The format of the LoadColorList method is:
2724 %
2725 %      MagickBooleanType LoadColorList(const char *xml,const char *filename,
2726 %        const unsigned long depth,ExceptionInfo *exception)
2727 %
2728 %  A description of each parameter follows:
2729 %
2730 %    o xml:  The color list in XML format.
2731 %
2732 %    o filename:  The color list filename.
2733 %
2734 %    o depth: depth of <include /> statements.
2735 %
2736 %    o exception: return any errors or warnings in this structure.
2737 %
2738 */
2739 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
2740   const unsigned long depth,ExceptionInfo *exception)
2741 {
2742   char
2743     keyword[MaxTextExtent],
2744     *token;
2745
2746   ColorInfo
2747     *color_info;
2748
2749   const char
2750     *q;
2751
2752   MagickBooleanType
2753     status;
2754
2755   /*
2756     Load the color map file.
2757   */
2758   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2759     "Loading color file \"%s\" ...",filename);
2760   if (xml == (char *) NULL)
2761     return(MagickFalse);
2762   if (color_list == (LinkedListInfo *) NULL)
2763     {
2764       color_list=NewLinkedList(0);
2765       if (color_list == (LinkedListInfo *) NULL)
2766         {
2767           ThrowFileException(exception,ResourceLimitError,
2768             "MemoryAllocationFailed",filename);
2769           return(MagickFalse);
2770         }
2771     }
2772   status=MagickTrue;
2773   color_info=(ColorInfo *) NULL;
2774   token=AcquireString(xml);
2775   for (q=(char *) xml; *q != '\0'; )
2776   {
2777     /*
2778       Interpret XML.
2779     */
2780     GetMagickToken(q,&q,token);
2781     if (*token == '\0')
2782       break;
2783     (void) CopyMagickString(keyword,token,MaxTextExtent);
2784     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2785       {
2786         /*
2787           Doctype element.
2788         */
2789         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2790           GetMagickToken(q,&q,token);
2791         continue;
2792       }
2793     if (LocaleNCompare(keyword,"<!--",4) == 0)
2794       {
2795         /*
2796           Comment element.
2797         */
2798         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2799           GetMagickToken(q,&q,token);
2800         continue;
2801       }
2802     if (LocaleCompare(keyword,"<include") == 0)
2803       {
2804         /*
2805           Include element.
2806         */
2807         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2808         {
2809           (void) CopyMagickString(keyword,token,MaxTextExtent);
2810           GetMagickToken(q,&q,token);
2811           if (*token != '=')
2812             continue;
2813           GetMagickToken(q,&q,token);
2814           if (LocaleCompare(keyword,"file") == 0)
2815             {
2816               if (depth > 200)
2817                 (void) ThrowMagickException(exception,GetMagickModule(),
2818                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2819               else
2820                 {
2821                   char
2822                     path[MaxTextExtent],
2823                     *xml;
2824
2825                   GetPathComponent(filename,HeadPath,path);
2826                   if (*path != '\0')
2827                     (void) ConcatenateMagickString(path,DirectorySeparator,
2828                       MaxTextExtent);
2829                   if (*token == *DirectorySeparator)
2830                     (void) CopyMagickString(path,token,MaxTextExtent);
2831                   else
2832                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
2833                   xml=FileToString(path,~0,exception);
2834                   if (xml != (char *) NULL)
2835                     {
2836                       status=LoadColorList(xml,path,depth+1,exception);
2837                       xml=(char *) RelinquishMagickMemory(xml);
2838                     }
2839                 }
2840             }
2841         }
2842         continue;
2843       }
2844     if (LocaleCompare(keyword,"<color") == 0)
2845       {
2846         /*
2847           Color element.
2848         */
2849         color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
2850         if (color_info == (ColorInfo *) NULL)
2851           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2852         (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
2853         color_info->path=ConstantString(filename);
2854         color_info->signature=MagickSignature;
2855         continue;
2856       }
2857     if (color_info == (ColorInfo *) NULL)
2858       continue;
2859     if (LocaleCompare(keyword,"/>") == 0)
2860       {
2861         status=AppendValueToLinkedList(color_list,color_info);
2862         if (status == MagickFalse)
2863           (void) ThrowMagickException(exception,GetMagickModule(),
2864             ResourceLimitError,"MemoryAllocationFailed","`%s'",
2865             color_info->name);
2866         color_info=(ColorInfo *) NULL;
2867       }
2868     GetMagickToken(q,(const char **) NULL,token);
2869     if (*token != '=')
2870       continue;
2871     GetMagickToken(q,&q,token);
2872     GetMagickToken(q,&q,token);
2873     switch (*keyword)
2874     {
2875       case 'C':
2876       case 'c':
2877       {
2878         if (LocaleCompare((char *) keyword,"color") == 0)
2879           {
2880             (void) QueryMagickColor(token,&color_info->color,exception);
2881             break;
2882           }
2883         if (LocaleCompare((char *) keyword,"compliance") == 0)
2884           {
2885             long
2886               compliance;
2887
2888             compliance=color_info->compliance;
2889             if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
2890               compliance|=SVGCompliance;
2891             if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
2892               compliance|=X11Compliance;
2893             if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
2894               compliance|=XPMCompliance;
2895             color_info->compliance=(ComplianceType) compliance;
2896             break;
2897           }
2898         break;
2899       }
2900       case 'N':
2901       case 'n':
2902       {
2903         if (LocaleCompare((char *) keyword,"name") == 0)
2904           {
2905             color_info->name=ConstantString(token);
2906             break;
2907           }
2908         break;
2909       }
2910       case 'S':
2911       case 's':
2912       {
2913         if (LocaleCompare((char *) keyword,"stealth") == 0)
2914           {
2915             color_info->stealth=IsMagickTrue(token);
2916             break;
2917           }
2918         break;
2919       }
2920       default:
2921         break;
2922     }
2923   }
2924   token=(char *) RelinquishMagickMemory(token);
2925   return(status);
2926 }
2927 \f
2928 /*
2929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930 %                                                                             %
2931 %                                                                             %
2932 %                                                                             %
2933 %  L o a d C o l o r L i s t s                                                %
2934 %                                                                             %
2935 %                                                                             %
2936 %                                                                             %
2937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938 %
2939 %  LoadColorList() loads one or more color configuration file which provides a
2940 %  mapping between color attributes and a color name.
2941 %
2942 %  The format of the LoadColorLists method is:
2943 %
2944 %      MagickBooleanType LoadColorLists(const char *filename,
2945 %        ExceptionInfo *exception)
2946 %
2947 %  A description of each parameter follows:
2948 %
2949 %    o filename: the font file name.
2950 %
2951 %    o exception: return any errors or warnings in this structure.
2952 %
2953 */
2954 static MagickBooleanType LoadColorLists(const char *filename,
2955   ExceptionInfo *exception)
2956 {
2957 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
2958   return(LoadColorList(ColorMap,"built-in",0,exception));
2959 #else
2960   const StringInfo
2961     *option;
2962
2963   LinkedListInfo
2964     *options;
2965
2966   MagickStatusType
2967     status;
2968
2969   status=MagickFalse;
2970   options=GetConfigureOptions(filename,exception);
2971   option=(const StringInfo *) GetNextValueInLinkedList(options);
2972   while (option != (const StringInfo *) NULL)
2973   {
2974     status|=LoadColorList((const char *) GetStringInfoDatum(option),
2975       GetStringInfoPath(option),0,exception);
2976     option=(const StringInfo *) GetNextValueInLinkedList(options);
2977   }
2978   options=DestroyConfigureOptions(options);
2979   if ((color_list == (LinkedListInfo *) NULL) ||
2980       (IsLinkedListEmpty(color_list) != MagickFalse))
2981     status|=LoadColorList(ColorMap,"built-in",0,exception);
2982   return(status != 0 ? MagickTrue : MagickFalse);
2983 #endif
2984 }
2985 \f
2986 /*
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 %                                                                             %
2989 %                                                                             %
2990 %                                                                             %
2991 %   Q u e r y C o l o r D a t a b a s e                                       %
2992 %                                                                             %
2993 %                                                                             %
2994 %                                                                             %
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996 %
2997 %  QueryColorDatabase() returns the red, green, blue, and opacity intensities
2998 %  for a given color name.
2999 %
3000 %  The format of the QueryColorDatabase method is:
3001 %
3002 %      MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
3003 %        ExceptionInfo *exception)
3004 %
3005 %  A description of each parameter follows:
3006 %
3007 %    o name: the color name (e.g. white, blue, yellow).
3008 %
3009 %    o color: the red, green, blue, and opacity intensities values of the
3010 %      named color in this structure.
3011 %
3012 %    o exception: return any errors or warnings in this structure.
3013 %
3014 */
3015
3016 static inline double MagickMin(const double x,const double y)
3017 {
3018   if (x < y)
3019     return(x);
3020   return(y);
3021 }
3022
3023 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
3024   PixelPacket *color,ExceptionInfo *exception)
3025 {
3026   MagickBooleanType
3027     status;
3028
3029   MagickPixelPacket
3030     pixel;
3031
3032   status=QueryMagickColor(name,&pixel,exception);
3033   color->opacity=RoundToQuantum(pixel.opacity);
3034   if (pixel.colorspace == CMYKColorspace)
3035     {
3036       color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3037         QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
3038         pixel.index)+pixel.index))));
3039       color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3040         QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
3041         pixel.index)+pixel.index))));
3042       color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3043         QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
3044         pixel.index)+pixel.index))));
3045       return(status);
3046     }
3047   color->red=RoundToQuantum(pixel.red);
3048   color->green=RoundToQuantum(pixel.green);
3049   color->blue=RoundToQuantum(pixel.blue);
3050   return(status);
3051 }
3052 \f
3053 /*
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 %                                                                             %
3056 %                                                                             %
3057 %                                                                             %
3058 %  Q u e r y C o l o r n a m e                                                %
3059 %                                                                             %
3060 %                                                                             %
3061 %                                                                             %
3062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3063 %
3064 %  QueryColorname() returns a named color for the given color intensity.  If
3065 %  an exact match is not found, a rgb() color is returned instead.
3066 %
3067 %  The format of the QueryColorname method is:
3068 %
3069 %      MagickBooleanType QueryColorname(const Image *image,
3070 %        const PixelPacket *color,const ComplianceType compliance,char *name,
3071 %        ExceptionInfo *exception)
3072 %
3073 %  A description of each parameter follows.
3074 %
3075 %    o image: the image.
3076 %
3077 %    o color: the color intensities.
3078 %
3079 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
3080 %
3081 %    o name: Return the color name or hex value.
3082 %
3083 %    o exception: return any errors or warnings in this structure.
3084 %
3085 */
3086 MagickExport MagickBooleanType QueryColorname(const Image *image,
3087   const PixelPacket *color,const ComplianceType compliance,char *name,
3088   ExceptionInfo *exception)
3089 {
3090   MagickPixelPacket
3091     pixel;
3092
3093   GetMagickPixelPacket(image,&pixel);
3094   SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
3095   return(QueryMagickColorname(image,&pixel,compliance,name,exception));
3096 }
3097 \f
3098 /*
3099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100 %                                                                             %
3101 %                                                                             %
3102 %                                                                             %
3103 %   Q u e r y M a g i c k C o l o r                                           %
3104 %                                                                             %
3105 %                                                                             %
3106 %                                                                             %
3107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108 %
3109 %  QueryMagickColor() returns the red, green, blue, and opacity intensities
3110 %  for a given color name.
3111 %
3112 %  The format of the QueryMagickColor method is:
3113 %
3114 %      MagickBooleanType QueryMagickColor(const char *name,
3115 %        MagickPixelPacket *color,ExceptionInfo *exception)
3116 %
3117 %  A description of each parameter follows:
3118 %
3119 %    o name: the color name (e.g. white, blue, yellow).
3120 %
3121 %    o color: the red, green, blue, and opacity intensities values of the
3122 %      named color in this structure.
3123 %
3124 %    o exception: return any errors or warnings in this structure.
3125 %
3126 */
3127 MagickExport MagickBooleanType QueryMagickColor(const char *name,
3128   MagickPixelPacket *color,ExceptionInfo *exception)
3129 {
3130   GeometryInfo
3131     geometry_info;
3132
3133   long
3134     type;
3135
3136   MagickRealType
3137     scale;
3138
3139   MagickStatusType
3140     flags;
3141
3142   register const ColorInfo
3143     *p;
3144
3145   register long
3146     i;
3147
3148   /*
3149     Initialize color return value.
3150   */
3151   assert(name != (const char *) NULL);
3152   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
3153   assert(color != (MagickPixelPacket *) NULL);
3154   GetMagickPixelPacket((Image *) NULL,color);
3155   if ((name == (char *) NULL) || (*name == '\0'))
3156     name=BackgroundColor;
3157   while (isspace((int) ((unsigned char) *name)) != 0)
3158     name++;
3159   if (*name == '#')
3160     {
3161       char
3162         c;
3163
3164       LongPixelPacket
3165         pixel;
3166
3167       QuantumAny
3168         range;
3169
3170       unsigned long
3171         depth,
3172         n;
3173
3174       /*
3175         Parse hex color.
3176       */
3177       (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
3178       name++;
3179       for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
3180       if ((n % 3) == 0)
3181         {
3182           do
3183           {
3184             pixel.red=pixel.green;
3185             pixel.green=pixel.blue;
3186             pixel.blue=0;
3187             for (i=(long) (n/3-1); i >= 0; i--)
3188             {
3189               c=(*name++);
3190               pixel.blue<<=4;
3191               if ((c >= '0') && (c <= '9'))
3192                 pixel.blue|=(int) (c-'0');
3193               else
3194                 if ((c >= 'A') && (c <= 'F'))
3195                   pixel.blue|=(int) c-((int) 'A'-10);
3196                 else
3197                   if ((c >= 'a') && (c <= 'f'))
3198                     pixel.blue|=(int) c-((int) 'a'-10);
3199                   else
3200                     return(MagickFalse);
3201             }
3202           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3203           depth=4*(n/3);
3204         }
3205       else
3206         {
3207           if ((n % 4) != 0)
3208             {
3209               (void) ThrowMagickException(exception,GetMagickModule(),
3210                 OptionWarning,"UnrecognizedColor","`%s'",name);
3211               return(MagickFalse);
3212             }
3213           do
3214           {
3215             pixel.red=pixel.green;
3216             pixel.green=pixel.blue;
3217             pixel.blue=pixel.opacity;
3218             pixel.opacity=0;
3219             for (i=(long) (n/4-1); i >= 0; i--)
3220             {
3221               c=(*name++);
3222               pixel.opacity<<=4;
3223               if ((c >= '0') && (c <= '9'))
3224                 pixel.opacity|=(int) (c-'0');
3225               else
3226                 if ((c >= 'A') && (c <= 'F'))
3227                   pixel.opacity|=(int) c-((int) 'A'-10);
3228                 else
3229                   if ((c >= 'a') && (c <= 'f'))
3230                     pixel.opacity|=(int) c-((int) 'a'-10);
3231                   else
3232                     return(MagickFalse);
3233             }
3234           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3235           depth=4*(n/4);
3236         }
3237       color->colorspace=RGBColorspace;
3238       color->matte=MagickFalse;
3239       range=GetQuantumRange(depth);
3240       color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
3241       color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
3242       color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
3243       color->opacity=(MagickRealType) OpaqueOpacity;
3244       if ((n % 3) != 0)
3245         {
3246           color->matte=MagickTrue;
3247           color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
3248             pixel.opacity,range));
3249         }
3250       color->index=0.0;
3251       return(MagickTrue);
3252     }
3253   if (strchr(name,'(') != (char *) NULL)
3254     {
3255       char
3256         colorspace[MaxTextExtent];
3257
3258       /*
3259         Parse color of the form rgb(100,255,0).
3260       */
3261       (void) CopyMagickString(colorspace,name,MaxTextExtent);
3262       for (i=0; colorspace[i] != '\0'; i++)
3263         if (colorspace[i] == '(')
3264           break;
3265       colorspace[i--]='\0';
3266       LocaleLower(colorspace);
3267       color->matte=MagickFalse;
3268       if ((i > 0) && (colorspace[i] == 'a'))
3269         {
3270           colorspace[i]='\0';
3271           color->matte=MagickTrue;
3272         }
3273       type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
3274       if (type < 0)
3275         {
3276           (void) ThrowMagickException(exception,GetMagickModule(),
3277             OptionWarning,"UnrecognizedColor","`%s'",name);
3278           return(MagickFalse);
3279         }
3280       color->colorspace=(ColorspaceType) type;
3281       SetGeometryInfo(&geometry_info);
3282       flags=ParseGeometry(name+i+1,&geometry_info);
3283       scale=(MagickRealType) ScaleCharToQuantum(1);
3284       if ((flags & PercentValue) != 0)
3285         scale=(MagickRealType) (QuantumRange/100.0);
3286       if ((flags & RhoValue) != 0)
3287         color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
3288       if ((flags & SigmaValue) != 0)
3289         color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
3290       if ((flags & XiValue) != 0)
3291         color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
3292       color->opacity=(MagickRealType) OpaqueOpacity;
3293       if ((flags & PsiValue) != 0)
3294         {
3295           if (color->colorspace == CMYKColorspace)
3296             color->index=(MagickRealType) RoundToQuantum(scale*
3297               geometry_info.psi);
3298           else
3299             if (color->matte != MagickFalse)
3300               color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3301                 (QuantumRange-QuantumRange*geometry_info.psi));
3302         }
3303       if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
3304         color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3305           (QuantumRange-QuantumRange*geometry_info.chi));
3306       if (LocaleCompare(colorspace,"gray") == 0)
3307         {
3308           color->green=color->red;
3309           color->blue=color->red;
3310           if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
3311             color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3312               (QuantumRange-QuantumRange*geometry_info.sigma));
3313         }
3314       if (LocaleCompare(colorspace,"HSB") == 0)
3315         {
3316           PixelPacket
3317             pixel;
3318
3319           geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3320             360.0;
3321           scale=1.0/255.0;
3322           if ((flags & PercentValue) != 0)
3323             scale=1.0/100.0;
3324           geometry_info.sigma*=scale;
3325           geometry_info.xi*=scale;
3326           ConvertHSBToRGB(geometry_info.rho,geometry_info.sigma,
3327             geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3328           color->colorspace=RGBColorspace;
3329           color->red=(MagickRealType) pixel.red;
3330           color->green=(MagickRealType) pixel.green;
3331           color->blue=(MagickRealType) pixel.blue;
3332         }
3333       if (LocaleCompare(colorspace,"HSL") == 0)
3334         {
3335           PixelPacket
3336             pixel;
3337
3338           geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3339             360.0;
3340           scale=1.0/255.0;
3341           if ((flags & PercentValue) != 0)
3342             scale=1.0/100.0;
3343           geometry_info.sigma*=scale;
3344           geometry_info.xi*=scale;
3345           ConvertHSLToRGB(geometry_info.rho,geometry_info.sigma,
3346             geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3347           color->colorspace=RGBColorspace;
3348           color->red=(MagickRealType) pixel.red;
3349           color->green=(MagickRealType) pixel.green;
3350           color->blue=(MagickRealType) pixel.blue;
3351         }
3352       if (LocaleCompare(colorspace,"HWB") == 0)
3353         {
3354           PixelPacket
3355             pixel;
3356
3357           geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3358             360.0;
3359           scale=1.0/255.0;
3360           if ((flags & PercentValue) != 0)
3361             scale=1.0/100.0;
3362           geometry_info.sigma*=scale;
3363           geometry_info.xi*=scale;
3364           ConvertHWBToRGB(geometry_info.rho,geometry_info.sigma,
3365             geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3366           color->colorspace=RGBColorspace;
3367           color->red=(MagickRealType) pixel.red;
3368           color->green=(MagickRealType) pixel.green;
3369           color->blue=(MagickRealType) pixel.blue;
3370         }
3371       return(MagickTrue);
3372     }
3373   /*
3374     Parse named color.
3375   */
3376   p=GetColorInfo(name,exception);
3377   if (p == (const ColorInfo *) NULL)
3378     return(MagickFalse);
3379   color->colorspace=RGBColorspace;
3380   color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3381   color->red=(MagickRealType) p->color.red;
3382   color->green=(MagickRealType) p->color.green;
3383   color->blue=(MagickRealType) p->color.blue;
3384   color->opacity=(MagickRealType) p->color.opacity;
3385   color->index=0.0;
3386   return(MagickTrue);
3387 }
3388 \f
3389 /*
3390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391 %                                                                             %
3392 %                                                                             %
3393 %                                                                             %
3394 %  Q u e r y M a g i c k C o l o r n a m e                                    %
3395 %                                                                             %
3396 %                                                                             %
3397 %                                                                             %
3398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3399 %
3400 %  QueryMagickColorname() returns a named color for the given color intensity.
3401 %  If an exact match is not found, a hex value is returned instead.  For
3402 %  example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
3403 %  returns #dfdfdf.
3404 %
3405 %  The format of the QueryMagickColorname method is:
3406 %
3407 %      MagickBooleanType QueryMagickColorname(const Image *image,
3408 %        const PixelPacket *color,const ComplianceType compliance,char *name,
3409 %        ExceptionInfo *exception)
3410 %
3411 %  A description of each parameter follows.
3412 %
3413 %    o image: the image.
3414 %
3415 %    o color: the color intensities.
3416 %
3417 %    o Compliance: Adhere to this color standard: SVG, X11, or XPM.
3418 %
3419 %    o name: Return the color name or hex value.
3420 %
3421 %    o exception: return any errors or warnings in this structure.
3422 %
3423 */
3424 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
3425   const MagickPixelPacket *color,const ComplianceType compliance,
3426   char *name,ExceptionInfo *exception)
3427 {
3428   MagickPixelPacket
3429     pixel;
3430
3431   MagickRealType
3432     opacity;
3433
3434   register const ColorInfo
3435     *p;
3436
3437   *name='\0';
3438   pixel=(*color);
3439   if (compliance == XPMCompliance)
3440     {
3441       pixel.matte=MagickFalse;
3442       pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
3443       GetColorTuple(&pixel,MagickTrue,name);
3444       return(MagickTrue);
3445     }
3446   GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
3447     name);
3448   (void) GetColorInfo("*",exception);
3449   ResetLinkedListIterator(color_list);
3450   opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
3451   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3452   while (p != (const ColorInfo *) NULL)
3453   {
3454     if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
3455          (p->color.green == color->green) && (p->color.blue == color->blue) &&
3456          (p->color.opacity == opacity))
3457       {
3458         (void) CopyMagickString(name,p->name,MaxTextExtent);
3459         break;
3460       }
3461     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3462   }
3463   return(MagickTrue);
3464 }
3465 \f
3466 /*
3467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3468 %                                                                             %
3469 %                                                                             %
3470 %                                                                             %
3471 %  U n i q u e I m a g e C o l o r s                                          %
3472 %                                                                             %
3473 %                                                                             %
3474 %                                                                             %
3475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476 %
3477 %  UniqueImageColors() returns the unique colors of an image.
3478 %
3479 %  The format of the UniqueImageColors method is:
3480 %
3481 %      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
3482 %
3483 %  A description of each parameter follows.
3484 %
3485 %    o image: the image.
3486 %
3487 %    o exception: return any errors or warnings in this structure.
3488 %
3489 */
3490
3491 static void UniqueColorsToImage(Image *image,CubeInfo *cube_info,
3492   const NodeInfo *node_info,ExceptionInfo *exception)
3493 {
3494 #define UniqueColorsImageTag  "UniqueColors/Image"
3495
3496   register long
3497     i;
3498
3499   unsigned long
3500     number_children;
3501
3502   /*
3503     Traverse any children.
3504   */
3505   number_children=image->matte == MagickFalse ? 8UL : 16UL;
3506   for (i=0; i < (long) number_children; i++)
3507     if (node_info->child[i] != (NodeInfo *) NULL)
3508       UniqueColorsToImage(image,cube_info,node_info->child[i],exception);
3509   if (node_info->level == (MaxTreeDepth-1))
3510     {
3511       register ColorPacket
3512         *p;
3513
3514       register IndexPacket
3515         *__restrict indexes;
3516
3517       register PixelPacket
3518         *__restrict q;
3519
3520       p=node_info->list;
3521       for (i=0; i < (long) node_info->number_unique; i++)
3522       {
3523         q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception);
3524         if (q == (PixelPacket *) NULL)
3525           continue;
3526         indexes=GetAuthenticIndexQueue(image);
3527         *q=p->pixel;
3528         if (image->colorspace == CMYKColorspace)
3529           *indexes=p->index;
3530         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3531           break;
3532         cube_info->x++;
3533         p++;
3534       }
3535       if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
3536           (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse))
3537         (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress,
3538           cube_info->colors,image->client_data);
3539       cube_info->progress++;
3540     }
3541 }
3542
3543 MagickExport Image *UniqueImageColors(const Image *image,
3544   ExceptionInfo *exception)
3545 {
3546   CubeInfo
3547     *cube_info;
3548
3549   Image
3550     *unique_image;
3551
3552   cube_info=ClassifyImageColors(image,exception);
3553   if (cube_info == (CubeInfo *) NULL)
3554     return((Image *) NULL);
3555   unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
3556   if (unique_image == (Image *) NULL)
3557     return(unique_image);
3558   if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
3559     {
3560       InheritException(exception,&unique_image->exception);
3561       unique_image=DestroyImage(unique_image);
3562       return((Image *) NULL);
3563     }
3564   UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception);
3565   if (cube_info->colors < MaxColormapSize)
3566     {
3567       QuantizeInfo
3568         *quantize_info;
3569
3570       quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
3571       quantize_info->number_colors=MaxColormapSize;
3572       quantize_info->dither=MagickFalse;
3573       quantize_info->tree_depth=8;
3574       (void) QuantizeImage(quantize_info,unique_image);
3575       quantize_info=DestroyQuantizeInfo(quantize_info);
3576     }
3577   cube_info=DestroyCubeInfo(image,cube_info);
3578   return(unique_image);
3579 }