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