]> 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 (pixel->depth > 8)
685     {
686       (void) FormatMagickString(component,MaxTextExtent,"%g%%",
687         (double) (100.0*QuantumScale*color));
688       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
689       return;
690     }
691   (void) FormatMagickString(component,MaxTextExtent,"%d",
692     ScaleQuantumToChar(RoundToQuantum(color)));
693   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
694 }
695 \f
696 /*
697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698 %                                                                             %
699 %                                                                             %
700 %                                                                             %
701 +   D e f i n e I m a g e H i s t o g r a m                                   %
702 %                                                                             %
703 %                                                                             %
704 %                                                                             %
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 %
707 %  DefineImageHistogram() traverses the color cube tree and notes each colormap
708 %  entry.  A colormap entry is any node in the color cube tree where the
709 %  of unique colors is not zero.
710 %
711 %  The format of the DefineImageHistogram method is:
712 %
713 %      DefineImageHistogram(const Image *image,NodeInfo *node_info,
714 %        ColorPacket **unique_colors)
715 %
716 %  A description of each parameter follows.
717 %
718 %    o image: the image.
719 %
720 %    o node_info: the address of a structure of type NodeInfo which points to a
721 %      node in the color cube tree that is to be pruned.
722 %
723 %    o histogram: the image histogram.
724 %
725 */
726 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
727   ColorPacket **histogram)
728 {
729   register long
730     i;
731
732   unsigned long
733     number_children;
734
735   /*
736     Traverse any children.
737   */
738   number_children=image->matte == MagickFalse ? 8UL : 16UL;
739   for (i=0; i < (long) number_children; i++)
740     if (node_info->child[i] != (NodeInfo *) NULL)
741       DefineImageHistogram(image,node_info->child[i],histogram);
742   if (node_info->level == (MaxTreeDepth-1))
743     {
744       register ColorPacket
745         *p;
746
747       p=node_info->list;
748       for (i=0; i < (long) node_info->number_unique; i++)
749       {
750         (*histogram)->pixel=p->pixel;
751         (*histogram)->index=p->index;
752         (*histogram)->count=p->count;
753         (*histogram)++;
754         p++;
755       }
756     }
757 }
758 \f
759 /*
760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761 %                                                                             %
762 %                                                                             %
763 %                                                                             %
764 +   D e s t r o y C o l o r L i s t                                           %
765 %                                                                             %
766 %                                                                             %
767 %                                                                             %
768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 %
770 %  DestroyColorList() deallocates memory associated with the color list.
771 %
772 %  The format of the DestroyColorList method is:
773 %
774 %      DestroyColorList(void)
775 %
776 */
777
778 static void *DestroyColorElement(void *color_info)
779 {
780   register ColorInfo
781     *p;
782
783   p=(ColorInfo *) color_info;
784   if (p->path != (char *) NULL)
785     p->path=DestroyString(p->path);
786   if (p->name != (char *) NULL)
787     p->name=DestroyString(p->name);
788   p=(ColorInfo *) RelinquishMagickMemory(p);
789   return((void *) NULL);
790 }
791
792 MagickExport void DestroyColorList(void)
793 {
794   AcquireSemaphoreInfo(&color_semaphore);
795   if (color_list != (LinkedListInfo *) NULL)
796     color_list=DestroyLinkedList(color_list,DestroyColorElement);
797   instantiate_color=MagickFalse;
798   RelinquishSemaphoreInfo(color_semaphore);
799   DestroySemaphoreInfo(&color_semaphore);
800 }
801 \f
802 /*
803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804 %                                                                             %
805 %                                                                             %
806 %                                                                             %
807 +   D e s t r o y C u b e I n f o                                             %
808 %                                                                             %
809 %                                                                             %
810 %                                                                             %
811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812 %
813 %  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
814 %
815 %  The format of the DestroyCubeInfo method is:
816 %
817 %      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
818 %
819 %  A description of each parameter follows:
820 %
821 %    o image: the image.
822 %
823 %    o cube_info: the address of a structure of type CubeInfo.
824 %
825 */
826 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
827 {
828   register Nodes
829     *nodes;
830
831   /*
832     Release color cube tree storage.
833   */
834   DestroyColorCube(image,cube_info->root);
835   do
836   {
837     nodes=cube_info->node_queue->next;
838     cube_info->node_queue=(Nodes *)
839       RelinquishMagickMemory(cube_info->node_queue);
840     cube_info->node_queue=nodes;
841   } while (cube_info->node_queue != (Nodes *) NULL);
842   return((CubeInfo *) RelinquishMagickMemory(cube_info));
843 }
844 \f
845 /*
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847 %                                                                             %
848 %                                                                             %
849 %                                                                             %
850 +  D e s t r o y C o l o r C u b e                                            %
851 %                                                                             %
852 %                                                                             %
853 %                                                                             %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855 %
856 %  DestroyColorCube() traverses the color cube tree and frees the list of
857 %  unique colors.
858 %
859 %  The format of the DestroyColorCube method is:
860 %
861 %      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
862 %
863 %  A description of each parameter follows.
864 %
865 %    o image: the image.
866 %
867 %    o node_info: the address of a structure of type NodeInfo which points to a
868 %      node in the color cube tree that is to be pruned.
869 %
870 */
871 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
872 {
873   register long
874     i;
875
876   unsigned long
877     number_children;
878
879   /*
880     Traverse any children.
881   */
882   number_children=image->matte == MagickFalse ? 8UL : 16UL;
883   for (i=0; i < (long) number_children; i++)
884     if (node_info->child[i] != (NodeInfo *) NULL)
885       DestroyColorCube(image,node_info->child[i]);
886   if (node_info->list != (ColorPacket *) NULL)
887     node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
888 }
889 \f
890 /*
891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
892 %                                                                             %
893 %                                                                             %
894 %                                                                             %
895 +   G e t C o l o r I n f o                                                   %
896 %                                                                             %
897 %                                                                             %
898 %                                                                             %
899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900 %
901 %  GetColorInfo() searches the color list for the specified name and if found
902 %  returns attributes for that color.
903 %
904 %  The format of the GetColorInfo method is:
905 %
906 %      const PixelPacket *GetColorInfo(const char *name,
907 %        ExceptionInfo *exception)
908 %
909 %  A description of each parameter follows:
910 %
911 %    o color_info: search the color list for the specified name and if found
912 %      return attributes for that color.
913 %
914 %    o name: the color name.
915 %
916 %    o exception: return any errors or warnings in this structure.
917 %
918 */
919 MagickExport const ColorInfo *GetColorInfo(const char *name,
920   ExceptionInfo *exception)
921 {
922   char
923     colorname[MaxTextExtent];
924
925   register const ColorInfo
926     *p;
927
928   register char
929     *q;
930
931   assert(exception != (ExceptionInfo *) NULL);
932   if ((color_list == (LinkedListInfo *) NULL) ||
933       (instantiate_color == MagickFalse))
934     if (InitializeColorList(exception) == MagickFalse)
935       return((const ColorInfo *) NULL);
936   if ((color_list == (LinkedListInfo *) NULL) ||
937       (IsLinkedListEmpty(color_list) != MagickFalse))
938     return((const ColorInfo *) NULL);
939   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
940     return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
941   /*
942     Strip names of whitespace.
943   */
944   (void) CopyMagickString(colorname,name,MaxTextExtent);
945   for (q=colorname; *q != '\0'; q++)
946   {
947     if (isspace((int) ((unsigned char) *q)) == 0)
948       continue;
949     (void) CopyMagickString(q,q+1,MaxTextExtent);
950     q--;
951   }
952   /*
953     Search for color tag.
954   */
955   AcquireSemaphoreInfo(&color_semaphore);
956   ResetLinkedListIterator(color_list);
957   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
958   while (p != (const ColorInfo *) NULL)
959   {
960     if (LocaleCompare(colorname,p->name) == 0)
961       break;
962     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
963   }
964   if (p == (ColorInfo *) NULL)
965     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
966       "UnrecognizedColor","`%s'",name);
967   else
968     (void) InsertValueInLinkedList(color_list,0,
969       RemoveElementByValueFromLinkedList(color_list,p));
970   RelinquishSemaphoreInfo(color_semaphore);
971   return(p);
972 }
973 \f
974 /*
975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 %                                                                             %
977 %                                                                             %
978 %                                                                             %
979 %   G e t C o l o r I n f o L i s t                                           %
980 %                                                                             %
981 %                                                                             %
982 %                                                                             %
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 %
985 %  GetColorInfoList() returns any colors that match the specified pattern.
986 %
987 %  The format of the GetColorInfoList function is:
988 %
989 %      const ColorInfo **GetColorInfoList(const char *pattern,
990 %        unsigned long *number_colors,ExceptionInfo *exception)
991 %
992 %  A description of each parameter follows:
993 %
994 %    o pattern: Specifies a pointer to a text string containing a pattern.
995 %
996 %    o number_colors:  This integer returns the number of colors in the list.
997 %
998 %    o exception: return any errors or warnings in this structure.
999 %
1000 */
1001
1002 #if defined(__cplusplus) || defined(c_plusplus)
1003 extern "C" {
1004 #endif
1005
1006 static int ColorInfoCompare(const void *x,const void *y)
1007 {
1008   const ColorInfo
1009     **p,
1010     **q;
1011
1012   p=(const ColorInfo **) x,
1013   q=(const ColorInfo **) y;
1014   if (LocaleCompare((*p)->path,(*q)->path) == 0)
1015     return(LocaleCompare((*p)->name,(*q)->name));
1016   return(LocaleCompare((*p)->path,(*q)->path));
1017 }
1018
1019 #if defined(__cplusplus) || defined(c_plusplus)
1020 }
1021 #endif
1022
1023 MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
1024   unsigned long *number_colors,ExceptionInfo *exception)
1025 {
1026   const ColorInfo
1027     **colors;
1028
1029   register const ColorInfo
1030     *p;
1031
1032   register long
1033     i;
1034
1035   /*
1036     Allocate color list.
1037   */
1038   assert(pattern != (char *) NULL);
1039   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1040   assert(number_colors != (unsigned long *) NULL);
1041   *number_colors=0;
1042   p=GetColorInfo("*",exception);
1043   if (p == (const ColorInfo *) NULL)
1044     return((const ColorInfo **) NULL);
1045   colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
1046     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1047   if (colors == (const ColorInfo **) NULL)
1048     return((const ColorInfo **) NULL);
1049   /*
1050     Generate color list.
1051   */
1052   AcquireSemaphoreInfo(&color_semaphore);
1053   ResetLinkedListIterator(color_list);
1054   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1055   for (i=0; p != (const ColorInfo *) NULL; )
1056   {
1057     if ((p->stealth == MagickFalse) &&
1058         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1059       colors[i++]=p;
1060     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1061   }
1062   RelinquishSemaphoreInfo(color_semaphore);
1063   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
1064   colors[i]=(ColorInfo *) NULL;
1065   *number_colors=(unsigned long) i;
1066   return(colors);
1067 }
1068 \f
1069 /*
1070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071 %                                                                             %
1072 %                                                                             %
1073 %                                                                             %
1074 %   G e t C o l o r L i s t                                                   %
1075 %                                                                             %
1076 %                                                                             %
1077 %                                                                             %
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 %
1080 %  GetColorList() returns any colors that match the specified pattern.
1081 %
1082 %  The format of the GetColorList function is:
1083 %
1084 %      char **GetColorList(const char *pattern,unsigned long *number_colors,
1085 %        ExceptionInfo *exception)
1086 %
1087 %  A description of each parameter follows:
1088 %
1089 %    o pattern: Specifies a pointer to a text string containing a pattern.
1090 %
1091 %    o number_colors:  This integer returns the number of colors in the list.
1092 %
1093 %    o exception: return any errors or warnings in this structure.
1094 %
1095 */
1096
1097 #if defined(__cplusplus) || defined(c_plusplus)
1098 extern "C" {
1099 #endif
1100
1101 static int ColorCompare(const void *x,const void *y)
1102 {
1103   register const char
1104     **p,
1105     **q;
1106
1107   p=(const char **) x;
1108   q=(const char **) y;
1109   return(LocaleCompare(*p,*q));
1110 }
1111
1112 #if defined(__cplusplus) || defined(c_plusplus)
1113 }
1114 #endif
1115
1116 MagickExport char **GetColorList(const char *pattern,
1117   unsigned long *number_colors,ExceptionInfo *exception)
1118 {
1119   char
1120     **colors;
1121
1122   register const ColorInfo
1123     *p;
1124
1125   register long
1126     i;
1127
1128   /*
1129     Allocate color list.
1130   */
1131   assert(pattern != (char *) NULL);
1132   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1133   assert(number_colors != (unsigned long *) NULL);
1134   *number_colors=0;
1135   p=GetColorInfo("*",exception);
1136   if (p == (const ColorInfo *) NULL)
1137     return((char **) NULL);
1138   colors=(char **) AcquireQuantumMemory((size_t)
1139     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1140   if (colors == (char **) NULL)
1141     return((char **) NULL);
1142   /*
1143     Generate color list.
1144   */
1145   AcquireSemaphoreInfo(&color_semaphore);
1146   ResetLinkedListIterator(color_list);
1147   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1148   for (i=0; p != (const ColorInfo *) NULL; )
1149   {
1150     if ((p->stealth == MagickFalse) &&
1151         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1152       colors[i++]=ConstantString(p->name);
1153     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1154   }
1155   RelinquishSemaphoreInfo(color_semaphore);
1156   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
1157   colors[i]=(char *) NULL;
1158   *number_colors=(unsigned long) i;
1159   return(colors);
1160 }
1161 \f
1162 /*
1163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 %                                                                             %
1165 %                                                                             %
1166 %                                                                             %
1167 +   G e t C o l o r T u p l e                                                 %
1168 %                                                                             %
1169 %                                                                             %
1170 %                                                                             %
1171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172 %
1173 %  GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
1174 %  or hex string (e.g. #FF0000).
1175 %
1176 %  The format of the GetColorTuple method is:
1177 %
1178 %      GetColorTuple(const MagickPixelPacket *pixel,const MagickBooleanType hex,
1179 %        char *tuple)
1180 %
1181 %  A description of each parameter follows.
1182 %
1183 %    o pixel: the pixel.
1184 %
1185 %    o hex: A value other than zero returns the tuple in a hexidecimal format.
1186 %
1187 %    o tuple: Return the color tuple as this string.
1188 %
1189 */
1190
1191 static void ConcatentateHexColorComponent(const MagickPixelPacket *pixel,
1192   const ChannelType channel,char *tuple)
1193 {
1194   char
1195     component[MaxTextExtent];
1196
1197   MagickRealType
1198     color;
1199
1200   color=0.0;
1201   switch (channel)
1202   {
1203     case RedChannel:
1204     {
1205       color=pixel->red;
1206       break;
1207     }
1208     case GreenChannel:
1209     {
1210       color=pixel->green;
1211       break;
1212     }
1213     case BlueChannel:
1214     {
1215       color=pixel->blue;
1216       break;
1217     }
1218     case OpacityChannel:
1219     {
1220       color=(MagickRealType) QuantumRange-pixel->opacity;
1221       break;
1222     }
1223     case IndexChannel:
1224     {
1225       color=pixel->index;
1226       break;
1227     }
1228     default:
1229       break;
1230   }
1231   if (pixel->depth > 32)
1232     {
1233       (void) FormatMagickString(component,MaxTextExtent,"%08lX",
1234         ScaleQuantumToLong(RoundToQuantum(color)));
1235       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1236       return;
1237     }
1238   if (pixel->depth > 16)
1239     {
1240       (void) FormatMagickString(component,MaxTextExtent,"%08X",
1241         (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
1242       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1243       return;
1244     }
1245   if (pixel->depth > 8)
1246     {
1247       (void) FormatMagickString(component,MaxTextExtent,"%04X",
1248         ScaleQuantumToShort(RoundToQuantum(color)));
1249       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1250       return;
1251     }
1252   (void) FormatMagickString(component,MaxTextExtent,"%02X",
1253     ScaleQuantumToChar(RoundToQuantum(color)));
1254   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1255   return;
1256 }
1257
1258 MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
1259   const MagickBooleanType hex,char *tuple)
1260 {
1261   MagickPixelPacket
1262     color;
1263
1264   assert(pixel != (const MagickPixelPacket *) NULL);
1265   assert(tuple != (char *) NULL);
1266   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
1267   *tuple='\0';
1268   if (hex != MagickFalse)
1269     {
1270       /*
1271         Convert pixel to hex color.
1272       */
1273       (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
1274       ConcatentateHexColorComponent(pixel,RedChannel,tuple);
1275       ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
1276       ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
1277       if (pixel->colorspace == CMYKColorspace)
1278         ConcatentateHexColorComponent(pixel,IndexChannel,tuple);
1279       if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
1280         ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
1281       return;
1282     }
1283   /*
1284     Convert pixel to rgb() or cmyk() color.
1285   */
1286   color=(*pixel);
1287   if (color.depth > 8)
1288     {
1289 #define SVGCompliant(component) ((MagickRealType) \
1290    ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(component))));
1291
1292       MagickStatusType
1293         status;
1294
1295       /*
1296         SVG requires color depths > 8 expressed as percentages.
1297       */
1298       status=color.red == SVGCompliant(color.red);
1299       status&=color.green == SVGCompliant(color.green);
1300       status&=color.blue == SVGCompliant(color.blue);
1301       if (color.colorspace != CMYKColorspace)
1302         status&=color.index == SVGCompliant(color.index);
1303       if (color.matte != MagickFalse)
1304         status&=color.opacity == SVGCompliant(color.opacity);
1305       if (status != MagickFalse)
1306         color.depth=8;
1307     }
1308   (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
1309     MagickColorspaceOptions,(long) color.colorspace),MaxTextExtent);
1310   if (color.matte != MagickFalse)
1311     (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
1312   (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
1313   ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
1314   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1315   ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
1316   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1317   ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
1318   if (color.colorspace == CMYKColorspace)
1319     {
1320       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1321       ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple);
1322     }
1323   if (color.matte != MagickFalse)
1324     {
1325       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1326       ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
1327     }
1328   (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1329   LocaleLower(tuple);
1330   return;
1331 }
1332 \f
1333 /*
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 %                                                                             %
1336 %                                                                             %
1337 %                                                                             %
1338 +   G e t C u b e I n f o                                                     %
1339 %                                                                             %
1340 %                                                                             %
1341 %                                                                             %
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 %
1344 %  GetCubeInfo() initializes the CubeInfo data structure.
1345 %
1346 %  The format of the GetCubeInfo method is:
1347 %
1348 %      cube_info=GetCubeInfo()
1349 %
1350 %  A description of each parameter follows.
1351 %
1352 %    o cube_info: A pointer to the Cube structure.
1353 %
1354 */
1355 static CubeInfo *GetCubeInfo(void)
1356 {
1357   CubeInfo
1358     *cube_info;
1359
1360   /*
1361     Initialize tree to describe color cube.
1362   */
1363   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
1364   if (cube_info == (CubeInfo *) NULL)
1365     return((CubeInfo *) NULL);
1366   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
1367   /*
1368     Initialize root node.
1369   */
1370   cube_info->root=GetNodeInfo(cube_info,0);
1371   if (cube_info->root == (NodeInfo *) NULL)
1372     return((CubeInfo *) NULL);
1373   return(cube_info);
1374 }
1375 \f
1376 /*
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378 %                                                                             %
1379 %                                                                             %
1380 %                                                                             %
1381 %  G e t I m a g e H i s t o g r a m                                          %
1382 %                                                                             %
1383 %                                                                             %
1384 %                                                                             %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 %
1387 %  GetImageHistogram() returns the unique colors in an image.
1388 %
1389 %  The format of the GetImageHistogram method is:
1390 %
1391 %      unsigned long GetImageHistogram(const Image *image,
1392 %        unsigned long *number_colors,ExceptionInfo *exception)
1393 %
1394 %  A description of each parameter follows.
1395 %
1396 %    o image: the image.
1397 %
1398 %    o file:  Write a histogram of the color distribution to this file handle.
1399 %
1400 %    o exception: return any errors or warnings in this structure.
1401 %
1402 */
1403 MagickExport ColorPacket *GetImageHistogram(const Image *image,
1404   unsigned long *number_colors,ExceptionInfo *exception)
1405 {
1406   ColorPacket
1407     *histogram;
1408
1409   CubeInfo
1410     *cube_info;
1411
1412   *number_colors=0;
1413   histogram=(ColorPacket *) NULL;
1414   cube_info=ClassifyImageColors(image,exception);
1415   if (cube_info != (CubeInfo *) NULL)
1416     {
1417       histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
1418         sizeof(*histogram));
1419       if (histogram == (ColorPacket *) NULL)
1420         (void) ThrowMagickException(exception,GetMagickModule(),
1421           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1422       else
1423         {
1424           ColorPacket
1425             *root;
1426
1427           *number_colors=cube_info->colors;
1428           root=histogram;
1429           DefineImageHistogram(image,cube_info->root,&root);
1430         }
1431     }
1432   cube_info=DestroyCubeInfo(image,cube_info);
1433   return(histogram);
1434 }
1435 \f
1436 /*
1437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438 %                                                                             %
1439 %                                                                             %
1440 %                                                                             %
1441 +  G e t N o d e I n f o                                                      %
1442 %                                                                             %
1443 %                                                                             %
1444 %                                                                             %
1445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 %
1447 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
1448 %  presets all fields to zero.
1449 %
1450 %  The format of the GetNodeInfo method is:
1451 %
1452 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1453 %
1454 %  A description of each parameter follows.
1455 %
1456 %    o cube_info: A pointer to the CubeInfo structure.
1457 %
1458 %    o level: Specifies the level in the storage_class the node resides.
1459 %
1460 */
1461 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1462 {
1463   NodeInfo
1464     *node_info;
1465
1466   if (cube_info->free_nodes == 0)
1467     {
1468       Nodes
1469         *nodes;
1470
1471       /*
1472         Allocate a new nodes of nodes.
1473       */
1474       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
1475       if (nodes == (Nodes *) NULL)
1476         return((NodeInfo *) NULL);
1477       nodes->next=cube_info->node_queue;
1478       cube_info->node_queue=nodes;
1479       cube_info->node_info=nodes->nodes;
1480       cube_info->free_nodes=NodesInAList;
1481     }
1482   cube_info->free_nodes--;
1483   node_info=cube_info->node_info++;
1484   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
1485   node_info->level=level;
1486   return(node_info);
1487 }
1488 \f
1489 /*
1490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1491 %                                                                             %
1492 %                                                                             %
1493 %                                                                             %
1494 %  G e t N u m b e r C o l o r s                                              %
1495 %                                                                             %
1496 %                                                                             %
1497 %                                                                             %
1498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 %
1500 %  GetNumberColors() returns the number of unique colors in an image.
1501 %
1502 %  The format of the GetNumberColors method is:
1503 %
1504 %      unsigned long GetNumberColors(const Image *image,FILE *file,
1505 %        ExceptionInfo *exception)
1506 %
1507 %  A description of each parameter follows.
1508 %
1509 %    o image: the image.
1510 %
1511 %    o file:  Write a histogram of the color distribution to this file handle.
1512 %
1513 %    o exception: return any errors or warnings in this structure.
1514 %
1515 */
1516
1517 #if defined(__cplusplus) || defined(c_plusplus)
1518 extern "C" {
1519 #endif
1520
1521 static int HistogramCompare(const void *x,const void *y)
1522 {
1523   const ColorPacket
1524     *color_1,
1525     *color_2;
1526
1527   color_1=(const ColorPacket *) x;
1528   color_2=(const ColorPacket *) y;
1529   if (color_2->pixel.red != color_1->pixel.red)
1530     return((int) color_1->pixel.red-(int) color_2->pixel.red);
1531   if (color_2->pixel.green != color_1->pixel.green)
1532     return((int) color_1->pixel.green-(int) color_2->pixel.green);
1533   if (color_2->pixel.blue != color_1->pixel.blue)
1534     return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
1535   return((int) color_2->count-(int) color_1->count);
1536 }
1537
1538 #if defined(__cplusplus) || defined(c_plusplus)
1539 }
1540 #endif
1541
1542 MagickExport unsigned long GetNumberColors(const Image *image,FILE *file,
1543   ExceptionInfo *exception)
1544 {
1545 #define HistogramImageTag  "Histogram/Image"
1546
1547   char
1548     color[MaxTextExtent],
1549     hex[MaxTextExtent],
1550     tuple[MaxTextExtent];
1551
1552   ColorPacket
1553     *histogram;
1554
1555   MagickPixelPacket
1556     pixel;
1557
1558   register ColorPacket
1559     *p;
1560
1561   register long
1562     i;
1563
1564   unsigned long
1565     number_colors;
1566
1567   number_colors=0;
1568   if (file == (FILE *) NULL)
1569     {
1570       CubeInfo
1571         *cube_info;
1572
1573       cube_info=ClassifyImageColors(image,exception);
1574       if (cube_info != (CubeInfo *) NULL)
1575         number_colors=cube_info->colors;
1576       cube_info=DestroyCubeInfo(image,cube_info);
1577       return(number_colors);
1578     }
1579   histogram=GetImageHistogram(image,&number_colors,exception);
1580   if (histogram == (ColorPacket *) NULL)
1581     return(number_colors);
1582   qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1583     HistogramCompare);
1584   GetMagickPixelPacket(image,&pixel);
1585   p=histogram;
1586   for (i=0; i < (long) number_colors; i++)
1587   {
1588     SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel);
1589     (void) CopyMagickString(tuple,"(",MaxTextExtent);
1590     ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1591     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1592     ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1593     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1594     ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1595     if (pixel.colorspace == CMYKColorspace)
1596       {
1597         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1598         ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
1599       }
1600     if (pixel.matte != MagickFalse)
1601       {
1602         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1603         ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
1604       }
1605     (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1606     (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
1607     GetColorTuple(&pixel,MagickTrue,hex);
1608     (void) fprintf(file,MagickSizeFormat,p->count);
1609     (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
1610     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1611         (QuantumTick(i,number_colors) != MagickFalse))
1612       (void) image->progress_monitor(HistogramImageTag,i,number_colors,
1613         image->client_data);
1614     p++;
1615   }
1616   (void) fflush(file);
1617   histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
1618   return(number_colors);
1619 }
1620 \f
1621 /*
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 %                                                                             %
1624 %                                                                             %
1625 %                                                                             %
1626 +   I n i t i a l i z e C o l o r L i s t                                     %
1627 %                                                                             %
1628 %                                                                             %
1629 %                                                                             %
1630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 %
1632 %  InitializeColorList() initializes the color list.
1633 %
1634 %  The format of the InitializeColorList method is:
1635 %
1636 %      MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1637 %
1638 %  A description of each parameter follows.
1639 %
1640 %    o exception: return any errors or warnings in this structure.
1641 %
1642 */
1643 static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1644 {
1645   if ((color_list == (LinkedListInfo *) NULL) &&
1646       (instantiate_color == MagickFalse))
1647     {
1648       AcquireSemaphoreInfo(&color_semaphore);
1649       if ((color_list == (LinkedListInfo *) NULL) &&
1650           (instantiate_color == MagickFalse))
1651         {
1652           (void) LoadColorLists(ColorFilename,exception);
1653           instantiate_color=MagickTrue;
1654         }
1655       RelinquishSemaphoreInfo(color_semaphore);
1656     }
1657   return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1658 }
1659 \f
1660 /*
1661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662 %                                                                             %
1663 %                                                                             %
1664 %                                                                             %
1665 +   I s C o l o r S i m i l a r                                               %
1666 %                                                                             %
1667 %                                                                             %
1668 %                                                                             %
1669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1670 %
1671 %  IsColorSimilar() returns MagickTrue if the distance between two colors is
1672 %  less than the specified distance in a linear three dimensional color space.
1673 %  This method is used by ColorFloodFill() and other algorithms which
1674 %  compare two colors.
1675 %
1676 %  The format of the IsColorSimilar method is:
1677 %
1678 %      void IsColorSimilar(const Image *image,const PixelPacket *p,
1679 %        const PixelPacket *q)
1680 %
1681 %  A description of each parameter follows:
1682 %
1683 %    o image: the image.
1684 %
1685 %    o p: Pixel p.
1686 %
1687 %    o q: Pixel q.
1688 %
1689 */
1690
1691 static inline double MagickMax(const double x,const double y)
1692 {
1693   if (x > y)
1694     return(x);
1695   return(y);
1696 }
1697
1698 MagickExport MagickBooleanType IsColorSimilar(const Image *image,
1699   const PixelPacket *p,const PixelPacket *q)
1700 {
1701   MagickRealType
1702     fuzz,
1703     pixel;
1704
1705   register MagickRealType
1706     alpha,
1707     beta,
1708     distance;
1709
1710   if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
1711     return(IsColorEqual(p,q));
1712   fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
1713     MagickSQ1_2);
1714   alpha=1.0;
1715   beta=1.0;
1716   if (image->matte != MagickFalse)
1717     {
1718       alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1719       beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1720     }
1721   pixel=alpha*p->red-beta*q->red;
1722   distance=pixel*pixel;
1723   if (distance > fuzz)
1724     return(MagickFalse);
1725   pixel=alpha*p->green-beta*q->green;
1726   distance+=pixel*pixel;
1727   if (distance > fuzz)
1728     return(MagickFalse);
1729   pixel=alpha*p->blue-beta*q->blue;
1730   distance+=pixel*pixel;
1731   if (distance > fuzz)
1732     return(MagickFalse);
1733   return(MagickTrue);
1734 }
1735 \f
1736 /*
1737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738 %                                                                             %
1739 %                                                                             %
1740 %                                                                             %
1741 %     I s G r a y I m a g e                                                   %
1742 %                                                                             %
1743 %                                                                             %
1744 %                                                                             %
1745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746 %
1747 %  IsGrayImage() returns MagickTrue if all the pixels in the image have the
1748 %  same red, green, and blue intensities.
1749 %
1750 %  The format of the IsGrayImage method is:
1751 %
1752 %      MagickBooleanType IsGrayImage(const Image *image,
1753 %        ExceptionInfo *exception)
1754 %
1755 %  A description of each parameter follows:
1756 %
1757 %    o image: the image.
1758 %
1759 %    o exception: return any errors or warnings in this structure.
1760 %
1761 */
1762 MagickExport MagickBooleanType IsGrayImage(const Image *image,
1763   ExceptionInfo *exception)
1764 {
1765   ImageType
1766     type;
1767
1768   register const PixelPacket
1769     *p;
1770
1771   assert(image != (Image *) NULL);
1772   assert(image->signature == MagickSignature);
1773   if (image->debug != MagickFalse)
1774     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1775   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1776       (image->type == GrayscaleMatteType))
1777     return(MagickTrue);
1778   if (image->colorspace == CMYKColorspace)
1779     return(MagickFalse);
1780   type=BilevelType;
1781   switch (image->storage_class)
1782   {
1783     case DirectClass:
1784     case UndefinedClass:
1785     {
1786       long
1787         y;
1788
1789       register long
1790         x;
1791
1792       CacheView
1793         *image_view;
1794
1795       image_view=AcquireCacheView(image);
1796       for (y=0; y < (long) image->rows; y++)
1797       {
1798         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1799         if (p == (const PixelPacket *) NULL)
1800           break;
1801         for (x=0; x < (long) image->columns; x++)
1802         {
1803           if (IsGrayPixel(p) == MagickFalse)
1804             {
1805               type=UndefinedType;
1806               break;
1807             }
1808           if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1809             type=GrayscaleType;
1810           p++;
1811         }
1812         if (type == UndefinedType)
1813           break;
1814       }
1815       image_view=DestroyCacheView(image_view);
1816       break;
1817     }
1818     case PseudoClass:
1819     {
1820       register long
1821         i;
1822
1823       p=image->colormap;
1824       for (i=0; i < (long) image->colors; i++)
1825       {
1826         if (IsGrayPixel(p) == MagickFalse)
1827           {
1828             type=UndefinedType;
1829             break;
1830           }
1831         if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1832           type=GrayscaleType;
1833         p++;
1834       }
1835       break;
1836     }
1837   }
1838   if (type == UndefinedType)
1839     return(MagickFalse);
1840   ((Image *) image)->type=type;
1841   if ((type == GrayscaleType) && (image->matte != MagickFalse))
1842     ((Image *) image)->type=GrayscaleMatteType;
1843   return(MagickTrue);
1844 }
1845 \f
1846 /*
1847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1848 %                                                                             %
1849 %                                                                             %
1850 %                                                                             %
1851 %  I s H i s t o g r a m I m a g e                                            %
1852 %                                                                             %
1853 %                                                                             %
1854 %                                                                             %
1855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856 %
1857 %  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
1858 %  less.
1859 %
1860 %  The format of the IsHistogramImage method is:
1861 %
1862 %      MagickBooleanType IsHistogramImage(const Image *image,
1863 %        ExceptionInfo *exception)
1864 %
1865 %  A description of each parameter follows.
1866 %
1867 %    o image: the image.
1868 %
1869 %    o exception: return any errors or warnings in this structure.
1870 %
1871 */
1872 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
1873   ExceptionInfo *exception)
1874 {
1875 #define MaximumUniqueColors  1024
1876
1877   CubeInfo
1878     *cube_info;
1879
1880   long
1881     y;
1882
1883   MagickPixelPacket
1884     pixel,
1885     target;
1886
1887   register const IndexPacket
1888     *indexes;
1889
1890   register const PixelPacket
1891     *p;
1892
1893   register long
1894     x;
1895
1896   register NodeInfo
1897     *node_info;
1898
1899   register long
1900     i;
1901
1902   unsigned long
1903     id,
1904     index,
1905     level;
1906
1907   CacheView
1908     *image_view;
1909
1910   assert(image != (Image *) NULL);
1911   assert(image->signature == MagickSignature);
1912   if (image->debug != MagickFalse)
1913     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1914   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1915     return(MagickTrue);
1916   if (image->storage_class == PseudoClass)
1917     return(MagickFalse);
1918   /*
1919     Initialize color description tree.
1920   */
1921   cube_info=GetCubeInfo();
1922   if (cube_info == (CubeInfo *) NULL)
1923     {
1924       (void) ThrowMagickException(exception,GetMagickModule(),
1925         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1926       return(MagickFalse);
1927     }
1928   GetMagickPixelPacket(image,&pixel);
1929   GetMagickPixelPacket(image,&target);
1930   image_view=AcquireCacheView(image);
1931   for (y=0; y < (long) image->rows; y++)
1932   {
1933     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1934     if (p == (const PixelPacket *) NULL)
1935       break;
1936     indexes=GetCacheViewVirtualIndexQueue(image_view);
1937     for (x=0; x < (long) image->columns; x++)
1938     {
1939       /*
1940         Start at the root and proceed level by level.
1941       */
1942       node_info=cube_info->root;
1943       index=MaxTreeDepth-1;
1944       for (level=1; level < MaxTreeDepth; level++)
1945       {
1946         SetMagickPixelPacket(image,p,indexes+x,&pixel);
1947         id=ColorToNodeId(image,&pixel,index);
1948         if (node_info->child[id] == (NodeInfo *) NULL)
1949           {
1950             node_info->child[id]=GetNodeInfo(cube_info,level);
1951             if (node_info->child[id] == (NodeInfo *) NULL)
1952               {
1953                 (void) ThrowMagickException(exception,GetMagickModule(),
1954                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
1955                   image->filename);
1956                 break;
1957               }
1958           }
1959         node_info=node_info->child[id];
1960         index--;
1961       }
1962       if (level < MaxTreeDepth)
1963         break;
1964       for (i=0; i < (long) node_info->number_unique; i++)
1965       {
1966         SetMagickPixelPacket(image,&node_info->list[i].pixel,
1967           &node_info->list[i].index,&target);
1968         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
1969           break;
1970       }
1971       if (i < (long) node_info->number_unique)
1972         node_info->list[i].count++;
1973       else
1974         {
1975           /*
1976             Add this unique color to the color list.
1977           */
1978           if (node_info->number_unique == 0)
1979             node_info->list=(ColorPacket *) AcquireMagickMemory(
1980               sizeof(*node_info->list));
1981           else
1982             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
1983               (size_t) (i+1),sizeof(*node_info->list));
1984           if (node_info->list == (ColorPacket *) NULL)
1985             {
1986               (void) ThrowMagickException(exception,GetMagickModule(),
1987                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1988                 image->filename);
1989               break;
1990             }
1991           node_info->list[i].pixel=(*p);
1992           if ((image->colorspace == CMYKColorspace) ||
1993               (image->storage_class == PseudoClass))
1994             node_info->list[i].index=indexes[x];
1995           node_info->list[i].count=1;
1996           node_info->number_unique++;
1997           cube_info->colors++;
1998           if (cube_info->colors > MaximumUniqueColors)
1999             break;
2000         }
2001       p++;
2002     }
2003     if (x < (long) image->columns)
2004       break;
2005   }
2006   image_view=DestroyCacheView(image_view);
2007   cube_info=DestroyCubeInfo(image,cube_info);
2008   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2009 }
2010 \f
2011 /*
2012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 %                                                                             %
2014 %                                                                             %
2015 %                                                                             %
2016 +   I s I m a g e S i m i l a r                                               %
2017 %                                                                             %
2018 %                                                                             %
2019 %                                                                             %
2020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2021 %
2022 %  IsImageSimilar() returns true if the target is similar to a region of the
2023 %  image.
2024 %
2025 %  The format of the IsImageSimilar method is:
2026 %
2027 %      MagickBooleanType IsImageSimilar(const Image *image,
2028 %        const Image *target_image,long *x_offset,long *y_offset,
2029 %        ExceptionInfo *exception)
2030 %
2031 %  A description of each parameter follows:
2032 %
2033 %    o image: the image.
2034 %
2035 %    o target_image: the target image.
2036 %
2037 %    o x_offset: On input the starting x position to search for a match;
2038 %      on output the x position of the first match found.
2039 %
2040 %    o y_offset: On input the starting y position to search for a match;
2041 %      on output the y position of the first match found.
2042 %
2043 %    o exception: return any errors or warnings in this structure.
2044 %
2045 */
2046 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
2047   const Image *target_image,long *x_offset,long *y_offset,
2048   ExceptionInfo *exception)
2049 {
2050 #define SearchImageText  "  Searching image...  "
2051
2052   long
2053     j,
2054     y;
2055
2056   MagickBooleanType
2057     status;
2058
2059   MagickPixelPacket
2060     target,
2061     pixel;
2062
2063   register const PixelPacket
2064     *p,
2065     *q;
2066
2067   register const IndexPacket
2068     *indexes,
2069     *target_indexes;
2070
2071   register long
2072     i,
2073     x;
2074
2075   CacheView
2076     *image_view,
2077     *target_view;
2078
2079   assert(image != (Image *) NULL);
2080   assert(image->signature == MagickSignature);
2081   if (image->debug != MagickFalse)
2082     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2083   assert(target_image != (Image *) NULL);
2084   assert(target_image->signature == MagickSignature);
2085   assert(x_offset != (long *) NULL);
2086   assert(y_offset != (long *) NULL);
2087   assert(exception != (ExceptionInfo *) NULL);
2088   x=0;
2089   GetMagickPixelPacket(image,&pixel);
2090   GetMagickPixelPacket(image,&target);
2091   image_view=AcquireCacheView(image);
2092   target_view=AcquireCacheView(target_image);
2093   for (y=(*y_offset); y < (long) image->rows; y++)
2094   {
2095     for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
2096     {
2097       for (j=0; j < (long) target_image->rows; j++)
2098       {
2099         for (i=0; i < (long) target_image->columns; i++)
2100         {
2101           p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
2102           indexes=GetCacheViewVirtualIndexQueue(image_view);
2103           SetMagickPixelPacket(image,p,indexes,&pixel);
2104           q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
2105           target_indexes=GetCacheViewVirtualIndexQueue(target_view);
2106           SetMagickPixelPacket(image,q,target_indexes,&target);
2107           if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
2108             break;
2109         }
2110         if (i < (long) target_image->columns)
2111           break;
2112       }
2113       if (j == (long) target_image->rows)
2114         break;
2115     }
2116     if (x < (long) image->columns)
2117       break;
2118     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
2119         (QuantumTick(y,image->rows) != MagickFalse))
2120       {
2121         status=image->progress_monitor(SearchImageText,y,image->rows,
2122           image->client_data);
2123         if (status == MagickFalse)
2124           break;
2125       }
2126   }
2127   target_view=DestroyCacheView(target_view);
2128   image_view=DestroyCacheView(image_view);
2129   *x_offset=x;
2130   *y_offset=y;
2131   return(y < (long) image->rows ? MagickTrue : MagickFalse);
2132 }
2133 \f
2134 /*
2135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2136 %                                                                             %
2137 %                                                                             %
2138 %                                                                             %
2139 +   I s M a g i c k C o l o r S i m i l a r                                   %
2140 %                                                                             %
2141 %                                                                             %
2142 %                                                                             %
2143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2144 %
2145 %  IsMagickColorSimilar() returns true if the distance between two colors is
2146 %  less than the specified distance in a linear three dimensional color space.
2147 %  This method is used by ColorFloodFill() and other algorithms which
2148 %  compare two colors.
2149 %
2150 %  The format of the IsMagickColorSimilar method is:
2151 %
2152 %      MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2153 %        const MagickPixelPacket *q)
2154 %
2155 %  A description of each parameter follows:
2156 %
2157 %    o p: Pixel p.
2158 %
2159 %    o q: Pixel q.
2160 %
2161 */
2162 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2163   const MagickPixelPacket *q)
2164 {
2165   MagickRealType
2166     fuzz,
2167     pixel;
2168
2169   register MagickRealType
2170     alpha,
2171     beta,
2172     distance;
2173
2174   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
2175     return(IsMagickColorEqual(p,q));
2176   if (p->fuzz == 0.0)
2177     fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2178   else
2179     if (q->fuzz == 0.0)
2180       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
2181     else
2182       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2183   alpha=1.0;
2184   if (p->matte != MagickFalse)
2185     alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
2186   beta=1.0;
2187   if (q->matte != MagickFalse)
2188     beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
2189   if (p->colorspace == CMYKColorspace)
2190     {
2191       alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
2192       beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
2193     }
2194   pixel=alpha*p->red-beta*q->red;
2195   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
2196       (p->colorspace == HWBColorspace))
2197     {
2198       if (fabs(p->red-q->red) > (QuantumRange/2))
2199         {
2200           if (p->red > (QuantumRange/2))
2201             pixel=alpha*(p->red-QuantumRange)-beta*q->red;
2202           else
2203             pixel=alpha*p->red-beta*(q->red-QuantumRange);
2204         }
2205         pixel*=2;
2206      }
2207   distance=pixel*pixel;
2208   if (distance > fuzz)
2209     return(MagickFalse);
2210   pixel=alpha*p->green-beta*q->green;
2211   distance+=pixel*pixel;
2212   if (distance > fuzz)
2213     return(MagickFalse);
2214   pixel=alpha*p->blue-beta*q->blue;
2215   distance+=pixel*pixel;
2216   if (distance > fuzz)
2217     return(MagickFalse);
2218   pixel=p->opacity-q->opacity;
2219   distance+=pixel*pixel;
2220   if (distance > fuzz)
2221     return(MagickFalse);
2222   return(MagickTrue);
2223 }
2224 \f
2225 /*
2226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2227 %                                                                             %
2228 %                                                                             %
2229 %                                                                             %
2230 %   I s M o n o c h r o m e I m a g e                                         %
2231 %                                                                             %
2232 %                                                                             %
2233 %                                                                             %
2234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2235 %
2236 %  IsMonochromeImage() returns MagickTrue if all the pixels in the image have
2237 %  the same red, green, and blue intensities and the intensity is either
2238 %  0 or QuantumRange.
2239 %
2240 %  The format of the IsMonochromeImage method is:
2241 %
2242 %      MagickBooleanType IsMonochromeImage(const Image *image,
2243 %        ExceptionInfo *exception)
2244 %
2245 %  A description of each parameter follows:
2246 %
2247 %    o image: the image.
2248 %
2249 %    o exception: return any errors or warnings in this structure.
2250 %
2251 */
2252 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
2253   ExceptionInfo *exception)
2254 {
2255   ImageType
2256     type;
2257
2258   register const PixelPacket
2259     *p;
2260
2261   assert(image != (Image *) NULL);
2262   assert(image->signature == MagickSignature);
2263   if (image->debug != MagickFalse)
2264     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2265   if (image->type == BilevelType)
2266     return(MagickTrue);
2267   if (image->colorspace == CMYKColorspace)
2268     return(MagickFalse);
2269   type=BilevelType;
2270   switch (image->storage_class)
2271   {
2272     case DirectClass:
2273     case UndefinedClass:
2274     {
2275       long
2276         y;
2277
2278       register long
2279         x;
2280
2281       CacheView
2282         *image_view;
2283
2284       image_view=AcquireCacheView(image);
2285       for (y=0; y < (long) image->rows; y++)
2286       {
2287         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2288         if (p == (const PixelPacket *) NULL)
2289           break;
2290         for (x=0; x < (long) image->columns; x++)
2291         {
2292           if (IsMonochromePixel(p) == MagickFalse)
2293             {
2294               type=UndefinedType;
2295               break;
2296             }
2297           p++;
2298         }
2299         if (type == UndefinedType)
2300           break;
2301       }
2302       image_view=DestroyCacheView(image_view);
2303       if (y == (long) image->rows)
2304         ((Image *) image)->type=BilevelType;
2305       break;
2306     }
2307     case PseudoClass:
2308     {
2309       register long
2310         i;
2311
2312       p=image->colormap;
2313       for (i=0; i < (long) image->colors; i++)
2314       {
2315         if (IsMonochromePixel(p) == MagickFalse)
2316           {
2317             type=UndefinedType;
2318             break;
2319           }
2320         p++;
2321       }
2322       break;
2323     }
2324   }
2325   if (type == UndefinedType)
2326     return(MagickFalse);
2327   ((Image *) image)->type=type;
2328   return(MagickTrue);
2329 }
2330 \f
2331 /*
2332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333 %                                                                             %
2334 %                                                                             %
2335 %                                                                             %
2336 +   I s O p a c i t y S i m i l a r                                           %
2337 %                                                                             %
2338 %                                                                             %
2339 %                                                                             %
2340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2341 %
2342 %  IsOpacitySimilar() returns true if the distance between two opacity
2343 %  values is less than the specified distance in a linear color space.  This
2344 %  method is used by MatteFloodFill() and other algorithms which compare
2345 %  two opacity values.
2346 %
2347 %  The format of the IsOpacitySimilar method is:
2348 %
2349 %      void IsOpacitySimilar(const Image *image,const PixelPacket *p,
2350 %        const PixelPacket *q)
2351 %
2352 %  A description of each parameter follows:
2353 %
2354 %    o image: the image.
2355 %
2356 %    o p: Pixel p.
2357 %
2358 %    o q: Pixel q.
2359 %
2360 */
2361 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
2362   const PixelPacket *p,const PixelPacket *q)
2363 {
2364   MagickRealType
2365     fuzz,
2366     pixel;
2367
2368   register MagickRealType
2369     distance;
2370
2371   if (image->matte == MagickFalse)
2372     return(MagickTrue);
2373   if (p->opacity == q->opacity)
2374     return(MagickTrue);
2375   fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
2376   pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
2377   distance=pixel*pixel;
2378   if (distance > fuzz)
2379     return(MagickFalse);
2380   return(MagickTrue);
2381 }
2382 \f
2383 /*
2384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2385 %                                                                             %
2386 %                                                                             %
2387 %                                                                             %
2388 %     I s O p a q u e I m a g e                                               %
2389 %                                                                             %
2390 %                                                                             %
2391 %                                                                             %
2392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393 %
2394 %  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
2395 %  an opacity value other than opaque (0).
2396 %
2397 %  The format of the IsOpaqueImage method is:
2398 %
2399 %      MagickBooleanType IsOpaqueImage(const Image *image,
2400 %        ExceptionInfo *exception)
2401 %
2402 %  A description of each parameter follows:
2403 %
2404 %    o image: the image.
2405 %
2406 %    o exception: return any errors or warnings in this structure.
2407 %
2408 */
2409 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
2410   ExceptionInfo *exception)
2411 {
2412   long
2413     y;
2414
2415   register const PixelPacket
2416     *p;
2417
2418   register long
2419     x;
2420
2421   CacheView
2422     *image_view;
2423
2424   /*
2425     Determine if image is opaque.
2426   */
2427   assert(image != (Image *) NULL);
2428   assert(image->signature == MagickSignature);
2429   if (image->debug != MagickFalse)
2430     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2431   if (image->matte == MagickFalse)
2432     return(MagickTrue);
2433   image_view=AcquireCacheView(image);
2434   for (y=0; y < (long) image->rows; y++)
2435   {
2436     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2437     if (p == (const PixelPacket *) NULL)
2438       break;
2439     for (x=0; x < (long) image->columns; x++)
2440     {
2441       if (p->opacity != OpaqueOpacity)
2442         break;
2443       p++;
2444     }
2445     if (x < (long) image->columns)
2446      break;
2447   }
2448   image_view=DestroyCacheView(image_view);
2449   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2450 }
2451 \f
2452 /*
2453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2454 %                                                                             %
2455 %                                                                             %
2456 %                                                                             %
2457 %  I s P a l e t t e I m a g e                                                %
2458 %                                                                             %
2459 %                                                                             %
2460 %                                                                             %
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462 %
2463 %  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
2464 %  unique colors or less.
2465 %
2466 %  The format of the IsPaletteImage method is:
2467 %
2468 %      MagickBooleanType IsPaletteImage(const Image *image,
2469 %        ExceptionInfo *exception)
2470 %
2471 %  A description of each parameter follows.
2472 %
2473 %    o image: the image.
2474 %
2475 %    o exception: return any errors or warnings in this structure.
2476 %
2477 */
2478 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
2479   ExceptionInfo *exception)
2480 {
2481   CubeInfo
2482     *cube_info;
2483
2484   long
2485     y;
2486
2487   MagickPixelPacket
2488     pixel,
2489     target;
2490
2491   register const IndexPacket
2492     *indexes;
2493
2494   register const PixelPacket
2495     *p;
2496
2497   register long
2498     x;
2499
2500   register NodeInfo
2501     *node_info;
2502
2503   register long
2504     i;
2505
2506   unsigned long
2507     id,
2508     index,
2509     level;
2510
2511   CacheView
2512     *image_view;
2513
2514   assert(image != (Image *) NULL);
2515   assert(image->signature == MagickSignature);
2516   if (image->debug != MagickFalse)
2517     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2518   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
2519     return(MagickTrue);
2520   if (image->storage_class == PseudoClass)
2521     return(MagickFalse);
2522   /*
2523     Initialize color description tree.
2524   */
2525   cube_info=GetCubeInfo();
2526   if (cube_info == (CubeInfo *) NULL)
2527     {
2528       (void) ThrowMagickException(exception,GetMagickModule(),
2529         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2530       return(MagickFalse);
2531     }
2532   GetMagickPixelPacket(image,&pixel);
2533   GetMagickPixelPacket(image,&target);
2534   image_view=AcquireCacheView(image);
2535   for (y=0; y < (long) image->rows; y++)
2536   {
2537     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2538     if (p == (const PixelPacket *) NULL)
2539       break;
2540     indexes=GetCacheViewVirtualIndexQueue(image_view);
2541     for (x=0; x < (long) image->columns; x++)
2542     {
2543       /*
2544         Start at the root and proceed level by level.
2545       */
2546       node_info=cube_info->root;
2547       index=MaxTreeDepth-1;
2548       for (level=1; level < MaxTreeDepth; level++)
2549       {
2550         SetMagickPixelPacket(image,p,indexes+x,&pixel);
2551         id=ColorToNodeId(image,&pixel,index);
2552         if (node_info->child[id] == (NodeInfo *) NULL)
2553           {
2554             node_info->child[id]=GetNodeInfo(cube_info,level);
2555             if (node_info->child[id] == (NodeInfo *) NULL)
2556               {
2557                 (void) ThrowMagickException(exception,GetMagickModule(),
2558                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
2559                   image->filename);
2560                 break;
2561               }
2562           }
2563         node_info=node_info->child[id];
2564         index--;
2565       }
2566       if (level < MaxTreeDepth)
2567         break;
2568       for (i=0; i < (long) node_info->number_unique; i++)
2569       {
2570         SetMagickPixelPacket(image,&node_info->list[i].pixel,
2571           &node_info->list[i].index,&target);
2572         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
2573           break;
2574       }
2575       if (i < (long) node_info->number_unique)
2576         node_info->list[i].count++;
2577       else
2578         {
2579           /*
2580             Add this unique color to the color list.
2581           */
2582           if (node_info->number_unique == 0)
2583             node_info->list=(ColorPacket *) AcquireMagickMemory(
2584               sizeof(*node_info->list));
2585           else
2586             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
2587               (size_t) (i+1),sizeof(*node_info->list));
2588           if (node_info->list == (ColorPacket *) NULL)
2589             {
2590               (void) ThrowMagickException(exception,GetMagickModule(),
2591                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2592                 image->filename);
2593               break;
2594             }
2595           node_info->list[i].pixel=(*p);
2596           if ((image->colorspace == CMYKColorspace) ||
2597               (image->storage_class == PseudoClass))
2598             node_info->list[i].index=indexes[x];
2599           node_info->list[i].count=1;
2600           node_info->number_unique++;
2601           cube_info->colors++;
2602           if (cube_info->colors > 256)
2603             break;
2604         }
2605       p++;
2606     }
2607     if (x < (long) image->columns)
2608       break;
2609   }
2610   image_view=DestroyCacheView(image_view);
2611   cube_info=DestroyCubeInfo(image,cube_info);
2612   return(y < (long) image->rows ? MagickFalse : MagickTrue);
2613 }
2614 \f
2615 /*
2616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2617 %                                                                             %
2618 %                                                                             %
2619 %                                                                             %
2620 %  L i s t C o l o r I n f o                                                  %
2621 %                                                                             %
2622 %                                                                             %
2623 %                                                                             %
2624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625 %
2626 %  ListColorInfo() lists color names to the specified file.  Color names
2627 %  are a convenience.  Rather than defining a color by its red, green, and
2628 %  blue intensities just use a color name such as white, blue, or yellow.
2629 %
2630 %  The format of the ListColorInfo method is:
2631 %
2632 %      MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
2633 %
2634 %  A description of each parameter follows.
2635 %
2636 %    o file:  List color names to this file handle.
2637 %
2638 %    o exception: return any errors or warnings in this structure.
2639 %
2640 */
2641 MagickExport MagickBooleanType ListColorInfo(FILE *file,
2642   ExceptionInfo *exception)
2643 {
2644   char
2645     tuple[MaxTextExtent];
2646
2647   const char
2648     *path;
2649
2650   const ColorInfo
2651     **color_info;
2652
2653   register long
2654     i;
2655
2656   unsigned long
2657     number_colors;
2658
2659   /*
2660     List name and attributes of each color in the list.
2661   */
2662   if (file == (const FILE *) NULL)
2663     file=stdout;
2664   color_info=GetColorInfoList("*",&number_colors,exception);
2665   if (color_info == (const ColorInfo **) NULL)
2666     return(MagickFalse);
2667   path=(const char *) NULL;
2668   for (i=0; i < (long) number_colors; i++)
2669   {
2670     if (color_info[i]->stealth != MagickFalse)
2671       continue;
2672     if ((path == (const char *) NULL) ||
2673         (LocaleCompare(path,color_info[i]->path) != 0))
2674       {
2675         if (color_info[i]->path != (char *) NULL)
2676           (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
2677         (void) fprintf(file,"Name                  Color                  "
2678           "                       Compliance\n");
2679         (void) fprintf(file,"-------------------------------------------------"
2680           "------------------------------\n");
2681       }
2682     path=color_info[i]->path;
2683     (void) fprintf(file,"%-21.21s ",color_info[i]->name);
2684     GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
2685     (void) fprintf(file,"%-45.45s ",tuple);
2686     if ((color_info[i]->compliance & SVGCompliance) != 0)
2687       (void) fprintf(file,"SVG ");
2688     if ((color_info[i]->compliance & X11Compliance) != 0)
2689       (void) fprintf(file,"X11 ");
2690     if ((color_info[i]->compliance & XPMCompliance) != 0)
2691       (void) fprintf(file,"XPM ");
2692     (void) fprintf(file,"\n");
2693   }
2694   color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
2695   (void) fflush(file);
2696   return(MagickTrue);
2697 }
2698 \f
2699 /*
2700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2701 %                                                                             %
2702 %                                                                             %
2703 %                                                                             %
2704 +   L o a d C o l o r L i s t                                                 %
2705 %                                                                             %
2706 %                                                                             %
2707 %                                                                             %
2708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 %
2710 %  LoadColorList() loads the color configuration file which provides a mapping
2711 %  between color attributes and a color name.
2712 %
2713 %  The format of the LoadColorList method is:
2714 %
2715 %      MagickBooleanType LoadColorList(const char *xml,const char *filename,
2716 %        const unsigned long depth,ExceptionInfo *exception)
2717 %
2718 %  A description of each parameter follows:
2719 %
2720 %    o xml:  The color list in XML format.
2721 %
2722 %    o filename:  The color list filename.
2723 %
2724 %    o depth: depth of <include /> statements.
2725 %
2726 %    o exception: return any errors or warnings in this structure.
2727 %
2728 */
2729 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
2730   const unsigned long depth,ExceptionInfo *exception)
2731 {
2732   char
2733     keyword[MaxTextExtent],
2734     *token;
2735
2736   ColorInfo
2737     *color_info;
2738
2739   const char
2740     *q;
2741
2742   MagickBooleanType
2743     status;
2744
2745   /*
2746     Load the color map file.
2747   */
2748   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2749     "Loading color file \"%s\" ...",filename);
2750   if (xml == (char *) NULL)
2751     return(MagickFalse);
2752   if (color_list == (LinkedListInfo *) NULL)
2753     {
2754       color_list=NewLinkedList(0);
2755       if (color_list == (LinkedListInfo *) NULL)
2756         {
2757           ThrowFileException(exception,ResourceLimitError,
2758             "MemoryAllocationFailed",filename);
2759           return(MagickFalse);
2760         }
2761     }
2762   status=MagickTrue;
2763   color_info=(ColorInfo *) NULL;
2764   token=AcquireString(xml);
2765   for (q=(char *) xml; *q != '\0'; )
2766   {
2767     /*
2768       Interpret XML.
2769     */
2770     GetMagickToken(q,&q,token);
2771     if (*token == '\0')
2772       break;
2773     (void) CopyMagickString(keyword,token,MaxTextExtent);
2774     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2775       {
2776         /*
2777           Doctype element.
2778         */
2779         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2780           GetMagickToken(q,&q,token);
2781         continue;
2782       }
2783     if (LocaleNCompare(keyword,"<!--",4) == 0)
2784       {
2785         /*
2786           Comment element.
2787         */
2788         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2789           GetMagickToken(q,&q,token);
2790         continue;
2791       }
2792     if (LocaleCompare(keyword,"<include") == 0)
2793       {
2794         /*
2795           Include element.
2796         */
2797         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2798         {
2799           (void) CopyMagickString(keyword,token,MaxTextExtent);
2800           GetMagickToken(q,&q,token);
2801           if (*token != '=')
2802             continue;
2803           GetMagickToken(q,&q,token);
2804           if (LocaleCompare(keyword,"file") == 0)
2805             {
2806               if (depth > 200)
2807                 (void) ThrowMagickException(exception,GetMagickModule(),
2808                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2809               else
2810                 {
2811                   char
2812                     path[MaxTextExtent],
2813                     *xml;
2814
2815                   GetPathComponent(filename,HeadPath,path);
2816                   if (*path != '\0')
2817                     (void) ConcatenateMagickString(path,DirectorySeparator,
2818                       MaxTextExtent);
2819                   if (*token == *DirectorySeparator)
2820                     (void) CopyMagickString(path,token,MaxTextExtent);
2821                   else
2822                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
2823                   xml=FileToString(path,~0,exception);
2824                   if (xml != (char *) NULL)
2825                     {
2826                       status=LoadColorList(xml,path,depth+1,exception);
2827                       xml=(char *) RelinquishMagickMemory(xml);
2828                     }
2829                 }
2830             }
2831         }
2832         continue;
2833       }
2834     if (LocaleCompare(keyword,"<color") == 0)
2835       {
2836         /*
2837           Color element.
2838         */
2839         color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
2840         if (color_info == (ColorInfo *) NULL)
2841           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2842         (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
2843         color_info->path=ConstantString(filename);
2844         color_info->signature=MagickSignature;
2845         continue;
2846       }
2847     if (color_info == (ColorInfo *) NULL)
2848       continue;
2849     if (LocaleCompare(keyword,"/>") == 0)
2850       {
2851         status=AppendValueToLinkedList(color_list,color_info);
2852         if (status == MagickFalse)
2853           (void) ThrowMagickException(exception,GetMagickModule(),
2854             ResourceLimitError,"MemoryAllocationFailed","`%s'",
2855             color_info->name);
2856         color_info=(ColorInfo *) NULL;
2857       }
2858     GetMagickToken(q,(const char **) NULL,token);
2859     if (*token != '=')
2860       continue;
2861     GetMagickToken(q,&q,token);
2862     GetMagickToken(q,&q,token);
2863     switch (*keyword)
2864     {
2865       case 'C':
2866       case 'c':
2867       {
2868         if (LocaleCompare((char *) keyword,"color") == 0)
2869           {
2870             (void) QueryMagickColor(token,&color_info->color,exception);
2871             break;
2872           }
2873         if (LocaleCompare((char *) keyword,"compliance") == 0)
2874           {
2875             long
2876               compliance;
2877
2878             compliance=color_info->compliance;
2879             if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
2880               compliance|=SVGCompliance;
2881             if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
2882               compliance|=X11Compliance;
2883             if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
2884               compliance|=XPMCompliance;
2885             color_info->compliance=(ComplianceType) compliance;
2886             break;
2887           }
2888         break;
2889       }
2890       case 'N':
2891       case 'n':
2892       {
2893         if (LocaleCompare((char *) keyword,"name") == 0)
2894           {
2895             color_info->name=ConstantString(token);
2896             break;
2897           }
2898         break;
2899       }
2900       case 'S':
2901       case 's':
2902       {
2903         if (LocaleCompare((char *) keyword,"stealth") == 0)
2904           {
2905             color_info->stealth=IsMagickTrue(token);
2906             break;
2907           }
2908         break;
2909       }
2910       default:
2911         break;
2912     }
2913   }
2914   token=(char *) RelinquishMagickMemory(token);
2915   return(status);
2916 }
2917 \f
2918 /*
2919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920 %                                                                             %
2921 %                                                                             %
2922 %                                                                             %
2923 %  L o a d C o l o r L i s t s                                                %
2924 %                                                                             %
2925 %                                                                             %
2926 %                                                                             %
2927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2928 %
2929 %  LoadColorList() loads one or more color configuration file which provides a
2930 %  mapping between color attributes and a color name.
2931 %
2932 %  The format of the LoadColorLists method is:
2933 %
2934 %      MagickBooleanType LoadColorLists(const char *filename,
2935 %        ExceptionInfo *exception)
2936 %
2937 %  A description of each parameter follows:
2938 %
2939 %    o filename: the font file name.
2940 %
2941 %    o exception: return any errors or warnings in this structure.
2942 %
2943 */
2944 static MagickBooleanType LoadColorLists(const char *filename,
2945   ExceptionInfo *exception)
2946 {
2947 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
2948   return(LoadColorList(ColorMap,"built-in",0,exception));
2949 #else
2950   const StringInfo
2951     *option;
2952
2953   LinkedListInfo
2954     *options;
2955
2956   MagickStatusType
2957     status;
2958
2959   status=MagickFalse;
2960   options=GetConfigureOptions(filename,exception);
2961   option=(const StringInfo *) GetNextValueInLinkedList(options);
2962   while (option != (const StringInfo *) NULL)
2963   {
2964     status|=LoadColorList((const char *) GetStringInfoDatum(option),
2965       GetStringInfoPath(option),0,exception);
2966     option=(const StringInfo *) GetNextValueInLinkedList(options);
2967   }
2968   options=DestroyConfigureOptions(options);
2969   if ((color_list == (LinkedListInfo *) NULL) ||
2970       (IsLinkedListEmpty(color_list) != MagickFalse))
2971     status|=LoadColorList(ColorMap,"built-in",0,exception);
2972   return(status != 0 ? MagickTrue : MagickFalse);
2973 #endif
2974 }
2975 \f
2976 /*
2977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2978 %                                                                             %
2979 %                                                                             %
2980 %                                                                             %
2981 %   Q u e r y C o l o r D a t a b a s e                                       %
2982 %                                                                             %
2983 %                                                                             %
2984 %                                                                             %
2985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2986 %
2987 %  QueryColorDatabase() returns the red, green, blue, and opacity intensities
2988 %  for a given color name.
2989 %
2990 %  The format of the QueryColorDatabase method is:
2991 %
2992 %      MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
2993 %        ExceptionInfo *exception)
2994 %
2995 %  A description of each parameter follows:
2996 %
2997 %    o name: the color name (e.g. white, blue, yellow).
2998 %
2999 %    o color: the red, green, blue, and opacity intensities values of the
3000 %      named color in this structure.
3001 %
3002 %    o exception: return any errors or warnings in this structure.
3003 %
3004 */
3005
3006 static inline double MagickMin(const double x,const double y)
3007 {
3008   if (x < y)
3009     return(x);
3010   return(y);
3011 }
3012
3013 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
3014   PixelPacket *color,ExceptionInfo *exception)
3015 {
3016   MagickBooleanType
3017     status;
3018
3019   MagickPixelPacket
3020     pixel;
3021
3022   status=QueryMagickColor(name,&pixel,exception);
3023   color->opacity=RoundToQuantum(pixel.opacity);
3024   if (pixel.colorspace == CMYKColorspace)
3025     {
3026       color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3027         QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
3028         pixel.index)+pixel.index))));
3029       color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3030         QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
3031         pixel.index)+pixel.index))));
3032       color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3033         QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
3034         pixel.index)+pixel.index))));
3035       return(status);
3036     }
3037   color->red=RoundToQuantum(pixel.red);
3038   color->green=RoundToQuantum(pixel.green);
3039   color->blue=RoundToQuantum(pixel.blue);
3040   return(status);
3041 }
3042 \f
3043 /*
3044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3045 %                                                                             %
3046 %                                                                             %
3047 %                                                                             %
3048 %  Q u e r y C o l o r n a m e                                                %
3049 %                                                                             %
3050 %                                                                             %
3051 %                                                                             %
3052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 %
3054 %  QueryColorname() returns a named color for the given color intensity.  If
3055 %  an exact match is not found, a rgb() color is returned instead.
3056 %
3057 %  The format of the QueryColorname method is:
3058 %
3059 %      MagickBooleanType QueryColorname(const Image *image,
3060 %        const PixelPacket *color,const ComplianceType compliance,char *name,
3061 %        ExceptionInfo *exception)
3062 %
3063 %  A description of each parameter follows.
3064 %
3065 %    o image: the image.
3066 %
3067 %    o color: the color intensities.
3068 %
3069 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
3070 %
3071 %    o name: Return the color name or hex value.
3072 %
3073 %    o exception: return any errors or warnings in this structure.
3074 %
3075 */
3076 MagickExport MagickBooleanType QueryColorname(const Image *image,
3077   const PixelPacket *color,const ComplianceType compliance,char *name,
3078   ExceptionInfo *exception)
3079 {
3080   MagickPixelPacket
3081     pixel;
3082
3083   GetMagickPixelPacket(image,&pixel);
3084   SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
3085   return(QueryMagickColorname(image,&pixel,compliance,name,exception));
3086 }
3087 \f
3088 /*
3089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3090 %                                                                             %
3091 %                                                                             %
3092 %                                                                             %
3093 %   Q u e r y M a g i c k C o l o r                                           %
3094 %                                                                             %
3095 %                                                                             %
3096 %                                                                             %
3097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3098 %
3099 %  QueryMagickColor() returns the red, green, blue, and opacity intensities
3100 %  for a given color name.
3101 %
3102 %  The format of the QueryMagickColor method is:
3103 %
3104 %      MagickBooleanType QueryMagickColor(const char *name,
3105 %        MagickPixelPacket *color,ExceptionInfo *exception)
3106 %
3107 %  A description of each parameter follows:
3108 %
3109 %    o name: the color name (e.g. white, blue, yellow).
3110 %
3111 %    o color: the red, green, blue, and opacity intensities values of the
3112 %      named color in this structure.
3113 %
3114 %    o exception: return any errors or warnings in this structure.
3115 %
3116 */
3117 MagickExport MagickBooleanType QueryMagickColor(const char *name,
3118   MagickPixelPacket *color,ExceptionInfo *exception)
3119 {
3120   GeometryInfo
3121     geometry_info;
3122
3123   long
3124     type;
3125
3126   MagickRealType
3127     scale;
3128
3129   MagickStatusType
3130     flags;
3131
3132   register const ColorInfo
3133     *p;
3134
3135   register long
3136     i;
3137
3138   /*
3139     Initialize color return value.
3140   */
3141   assert(name != (const char *) NULL);
3142   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
3143   assert(color != (MagickPixelPacket *) NULL);
3144   GetMagickPixelPacket((Image *) NULL,color);
3145   if ((name == (char *) NULL) || (*name == '\0'))
3146     name=BackgroundColor;
3147   while (isspace((int) ((unsigned char) *name)) != 0)
3148     name++;
3149   if (*name == '#')
3150     {
3151       char
3152         c;
3153
3154       LongPixelPacket
3155         pixel;
3156
3157       QuantumAny
3158         range;
3159
3160       unsigned long
3161         depth,
3162         n;
3163
3164       /*
3165         Parse hex color.
3166       */
3167       (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
3168       name++;
3169       for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
3170       if ((n % 3) == 0)
3171         {
3172           do
3173           {
3174             pixel.red=pixel.green;
3175             pixel.green=pixel.blue;
3176             pixel.blue=0;
3177             for (i=(long) (n/3-1); i >= 0; i--)
3178             {
3179               c=(*name++);
3180               pixel.blue<<=4;
3181               if ((c >= '0') && (c <= '9'))
3182                 pixel.blue|=(int) (c-'0');
3183               else
3184                 if ((c >= 'A') && (c <= 'F'))
3185                   pixel.blue|=(int) c-((int) 'A'-10);
3186                 else
3187                   if ((c >= 'a') && (c <= 'f'))
3188                     pixel.blue|=(int) c-((int) 'a'-10);
3189                   else
3190                     return(MagickFalse);
3191             }
3192           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3193           depth=4*(n/3);
3194         }
3195       else
3196         {
3197           if ((n % 4) != 0)
3198             {
3199               (void) ThrowMagickException(exception,GetMagickModule(),
3200                 OptionWarning,"UnrecognizedColor","`%s'",name);
3201               return(MagickFalse);
3202             }
3203           do
3204           {
3205             pixel.red=pixel.green;
3206             pixel.green=pixel.blue;
3207             pixel.blue=pixel.opacity;
3208             pixel.opacity=0;
3209             for (i=(long) (n/4-1); i >= 0; i--)
3210             {
3211               c=(*name++);
3212               pixel.opacity<<=4;
3213               if ((c >= '0') && (c <= '9'))
3214                 pixel.opacity|=(int) (c-'0');
3215               else
3216                 if ((c >= 'A') && (c <= 'F'))
3217                   pixel.opacity|=(int) c-((int) 'A'-10);
3218                 else
3219                   if ((c >= 'a') && (c <= 'f'))
3220                     pixel.opacity|=(int) c-((int) 'a'-10);
3221                   else
3222                     return(MagickFalse);
3223             }
3224           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3225           depth=4*(n/4);
3226         }
3227       color->colorspace=RGBColorspace;
3228       color->matte=MagickFalse;
3229       range=GetQuantumRange(depth);
3230       color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
3231       color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
3232       color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
3233       color->opacity=(MagickRealType) OpaqueOpacity;
3234       if ((n % 3) != 0)
3235         {
3236           color->matte=MagickTrue;
3237           color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
3238             pixel.opacity,range));
3239         }
3240       color->index=0.0;
3241       return(MagickTrue);
3242     }
3243   if (strchr(name,'(') != (char *) NULL)
3244     {
3245       char
3246         colorspace[MaxTextExtent];
3247
3248       /*
3249         Parse color of the form rgb(100,255,0).
3250       */
3251       (void) CopyMagickString(colorspace,name,MaxTextExtent);
3252       for (i=0; colorspace[i] != '\0'; i++)
3253         if (colorspace[i] == '(')
3254           break;
3255       colorspace[i--]='\0';
3256       LocaleLower(colorspace);
3257       color->matte=MagickFalse;
3258       if ((i > 0) && (colorspace[i] == 'a'))
3259         {
3260           colorspace[i]='\0';
3261           color->matte=MagickTrue;
3262         }
3263       type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
3264       if (type < 0)
3265         {
3266           (void) ThrowMagickException(exception,GetMagickModule(),
3267             OptionWarning,"UnrecognizedColor","`%s'",name);
3268           return(MagickFalse);
3269         }
3270       color->colorspace=(ColorspaceType) type;
3271       SetGeometryInfo(&geometry_info);
3272       flags=ParseGeometry(name+i+1,&geometry_info);
3273       scale=(MagickRealType) ScaleCharToQuantum(1);
3274       if ((flags & PercentValue) != 0)
3275         scale=(MagickRealType) (QuantumRange/100.0);
3276       if ((flags & RhoValue) != 0)
3277         color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
3278       if ((flags & SigmaValue) != 0)
3279         color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
3280       if ((flags & XiValue) != 0)
3281         color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
3282       color->opacity=(MagickRealType) OpaqueOpacity;
3283       if ((flags & PsiValue) != 0)
3284         {
3285           if (color->colorspace == CMYKColorspace)
3286             color->index=(MagickRealType) RoundToQuantum(scale*
3287               geometry_info.psi);
3288           else
3289             if (color->matte != MagickFalse)
3290               color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3291                 (QuantumRange-QuantumRange*geometry_info.psi));
3292         }
3293       if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
3294         color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3295           (QuantumRange-QuantumRange*geometry_info.chi));
3296       if (LocaleCompare(colorspace,"gray") == 0)
3297         {
3298           color->green=color->red;
3299           color->blue=color->red;
3300           if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
3301             color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3302               (QuantumRange-QuantumRange*geometry_info.sigma));
3303         }
3304       if ((LocaleCompare(colorspace,"HSB") == 0) ||
3305           (LocaleCompare(colorspace,"HSL") == 0) ||
3306           (LocaleCompare(colorspace,"HWB") == 0))
3307         {
3308           PixelPacket
3309             pixel;
3310
3311           scale=1.0/360.0;
3312           if ((flags & PercentValue) != 0)
3313             scale=1.0/100.0;
3314           geometry_info.rho*=360.0*scale;
3315           scale=1.0/255.0;
3316           if ((flags & PercentValue) != 0)
3317             scale=1.0/100.0;
3318           geometry_info.sigma*=scale;
3319           geometry_info.xi*=scale;
3320           if (LocaleCompare(colorspace,"HSB") == 0)
3321             ConvertHSBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3322               360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
3323               &pixel.green,&pixel.blue);
3324           else
3325             if (LocaleCompare(colorspace,"HSL") == 0)
3326               ConvertHSLToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3327                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
3328                 &pixel.green,&pixel.blue);
3329             else
3330               ConvertHWBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3331                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
3332                 &pixel.green,&pixel.blue);
3333           color->colorspace=RGBColorspace;
3334           color->red=(MagickRealType) pixel.red;
3335           color->green=(MagickRealType) pixel.green;
3336           color->blue=(MagickRealType) pixel.blue;
3337         }
3338       return(MagickTrue);
3339     }
3340   /*
3341     Parse named color.
3342   */
3343   p=GetColorInfo(name,exception);
3344   if (p == (const ColorInfo *) NULL)
3345     return(MagickFalse);
3346   color->colorspace=RGBColorspace;
3347   color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3348   color->red=(MagickRealType) p->color.red;
3349   color->green=(MagickRealType) p->color.green;
3350   color->blue=(MagickRealType) p->color.blue;
3351   color->opacity=(MagickRealType) p->color.opacity;
3352   color->index=0.0;
3353   return(MagickTrue);
3354 }
3355 \f
3356 /*
3357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3358 %                                                                             %
3359 %                                                                             %
3360 %                                                                             %
3361 %  Q u e r y M a g i c k C o l o r n a m e                                    %
3362 %                                                                             %
3363 %                                                                             %
3364 %                                                                             %
3365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3366 %
3367 %  QueryMagickColorname() returns a named color for the given color intensity.
3368 %  If an exact match is not found, a hex value is returned instead.  For
3369 %  example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
3370 %  returns #dfdfdf.
3371 %
3372 %  The format of the QueryMagickColorname method is:
3373 %
3374 %      MagickBooleanType QueryMagickColorname(const Image *image,
3375 %        const PixelPacket *color,const ComplianceType compliance,char *name,
3376 %        ExceptionInfo *exception)
3377 %
3378 %  A description of each parameter follows.
3379 %
3380 %    o image: the image.
3381 %
3382 %    o color: the color intensities.
3383 %
3384 %    o Compliance: Adhere to this color standard: SVG, X11, or XPM.
3385 %
3386 %    o name: Return the color name or hex value.
3387 %
3388 %    o exception: return any errors or warnings in this structure.
3389 %
3390 */
3391 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
3392   const MagickPixelPacket *color,const ComplianceType compliance,
3393   char *name,ExceptionInfo *exception)
3394 {
3395   MagickPixelPacket
3396     pixel;
3397
3398   MagickRealType
3399     opacity;
3400
3401   register const ColorInfo
3402     *p;
3403
3404   *name='\0';
3405   pixel=(*color);
3406   if (compliance == XPMCompliance)
3407     {
3408       pixel.matte=MagickFalse;
3409       pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
3410       GetColorTuple(&pixel,MagickTrue,name);
3411       return(MagickTrue);
3412     }
3413   GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
3414     name);
3415   (void) GetColorInfo("*",exception);
3416   ResetLinkedListIterator(color_list);
3417   opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
3418   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3419   while (p != (const ColorInfo *) NULL)
3420   {
3421     if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
3422          (p->color.green == color->green) && (p->color.blue == color->blue) &&
3423          (p->color.opacity == opacity))
3424       {
3425         (void) CopyMagickString(name,p->name,MaxTextExtent);
3426         break;
3427       }
3428     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3429   }
3430   return(MagickTrue);
3431 }
3432 \f
3433 /*
3434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3435 %                                                                             %
3436 %                                                                             %
3437 %                                                                             %
3438 %  U n i q u e I m a g e C o l o r s                                          %
3439 %                                                                             %
3440 %                                                                             %
3441 %                                                                             %
3442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3443 %
3444 %  UniqueImageColors() returns the unique colors of an image.
3445 %
3446 %  The format of the UniqueImageColors method is:
3447 %
3448 %      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
3449 %
3450 %  A description of each parameter follows.
3451 %
3452 %    o image: the image.
3453 %
3454 %    o exception: return any errors or warnings in this structure.
3455 %
3456 */
3457
3458 static void UniqueColorsToImage(Image *image,CubeInfo *cube_info,
3459   const NodeInfo *node_info,ExceptionInfo *exception)
3460 {
3461 #define UniqueColorsImageTag  "UniqueColors/Image"
3462
3463   register long
3464     i;
3465
3466   unsigned long
3467     number_children;
3468
3469   /*
3470     Traverse any children.
3471   */
3472   number_children=image->matte == MagickFalse ? 8UL : 16UL;
3473   for (i=0; i < (long) number_children; i++)
3474     if (node_info->child[i] != (NodeInfo *) NULL)
3475       UniqueColorsToImage(image,cube_info,node_info->child[i],exception);
3476   if (node_info->level == (MaxTreeDepth-1))
3477     {
3478       register ColorPacket
3479         *p;
3480
3481       register IndexPacket
3482         *__restrict indexes;
3483
3484       register PixelPacket
3485         *__restrict q;
3486
3487       p=node_info->list;
3488       for (i=0; i < (long) node_info->number_unique; i++)
3489       {
3490         q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception);
3491         if (q == (PixelPacket *) NULL)
3492           continue;
3493         indexes=GetAuthenticIndexQueue(image);
3494         *q=p->pixel;
3495         if (image->colorspace == CMYKColorspace)
3496           *indexes=p->index;
3497         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3498           break;
3499         cube_info->x++;
3500         p++;
3501       }
3502       if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
3503           (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse))
3504         (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress,
3505           cube_info->colors,image->client_data);
3506       cube_info->progress++;
3507     }
3508 }
3509
3510 MagickExport Image *UniqueImageColors(const Image *image,
3511   ExceptionInfo *exception)
3512 {
3513   CubeInfo
3514     *cube_info;
3515
3516   Image
3517     *unique_image;
3518
3519   cube_info=ClassifyImageColors(image,exception);
3520   if (cube_info == (CubeInfo *) NULL)
3521     return((Image *) NULL);
3522   unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
3523   if (unique_image == (Image *) NULL)
3524     return(unique_image);
3525   if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
3526     {
3527       InheritException(exception,&unique_image->exception);
3528       unique_image=DestroyImage(unique_image);
3529       return((Image *) NULL);
3530     }
3531   UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception);
3532   if (cube_info->colors < MaxColormapSize)
3533     {
3534       QuantizeInfo
3535         *quantize_info;
3536
3537       quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
3538       quantize_info->number_colors=MaxColormapSize;
3539       quantize_info->dither=MagickFalse;
3540       quantize_info->tree_depth=8;
3541       (void) QuantizeImage(quantize_info,unique_image);
3542       quantize_info=DestroyQuantizeInfo(quantize_info);
3543     }
3544   cube_info=DestroyCubeInfo(image,cube_info);
3545   return(unique_image);
3546 }