]> 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 \f
74 /*
75   Declare color map.
76 */
77 static const char
78   *ColorMap = (const char *)
79     "<?xml version=\"1.0\"?>"
80     "<colormap>"
81     "  <color name=\"none\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
82     "  <color name=\"black\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11, XPM\" />"
83     "  <color name=\"red\" color=\"rgb(255,0,0)\" compliance=\"SVG, X11, XPM\" />"
84     "  <color name=\"magenta\" color=\"rgb(255,0,255)\" compliance=\"SVG, X11, XPM\" />"
85     "  <color name=\"green\" color=\"rgb(0,128,0)\" compliance=\"SVG\" />"
86     "  <color name=\"cyan\" color=\"rgb(0,255,255)\" compliance=\"SVG, X11, XPM\" />"
87     "  <color name=\"blue\" color=\"rgb(0,0,255)\" compliance=\"SVG, X11, XPM\" />"
88     "  <color name=\"yellow\" color=\"rgb(255,255,0)\" compliance=\"SVG, X11, XPM\" />"
89     "  <color name=\"white\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
90     "  <color name=\"AliceBlue\" color=\"rgb(240,248,255)\" compliance=\"SVG, X11, XPM\" />"
91     "  <color name=\"AntiqueWhite\" color=\"rgb(250,235,215)\" compliance=\"SVG, X11, XPM\" />"
92     "  <color name=\"aqua\" color=\"rgb(0,255,255)\" compliance=\"SVG\" />"
93     "  <color name=\"aquamarine\" color=\"rgb(127,255,212)\" compliance=\"SVG, X11, XPM\" />"
94     "  <color name=\"azure\" color=\"rgb(240,255,255)\" compliance=\"SVG, X11, XPM\" />"
95     "  <color name=\"beige\" color=\"rgb(245,245,220)\" compliance=\"SVG, X11, XPM\" />"
96     "  <color name=\"bisque\" color=\"rgb(255,228,196)\" compliance=\"SVG, X11, XPM\" />"
97     "  <color name=\"BlanchedAlmond\" color=\"rgb(255,235,205)\" compliance=\"SVG, X11, XPM\" />"
98     "  <color name=\"BlueViolet\" color=\"rgb(138,43,226)\" compliance=\"SVG, X11, XPM\" />"
99     "  <color name=\"brown\" color=\"rgb(165,42,42)\" compliance=\"SVG, X11, XPM\" />"
100     "  <color name=\"burlywood\" color=\"rgb(222,184,135)\" compliance=\"SVG, X11, XPM\" />"
101     "  <color name=\"CadetBlue\" color=\"rgb(95,158,160)\" compliance=\"SVG, X11, XPM\" />"
102     "  <color name=\"chartreuse\" color=\"rgb(127,255,0)\" compliance=\"SVG, X11, XPM\" />"
103     "  <color name=\"chocolate\" color=\"rgb(210,105,30)\" compliance=\"SVG, X11, XPM\" />"
104     "  <color name=\"coral\" color=\"rgb(255,127,80)\" compliance=\"SVG, X11, XPM\" />"
105     "  <color name=\"CornflowerBlue\" color=\"rgb(100,149,237)\" compliance=\"SVG, X11, XPM\" />"
106     "  <color name=\"cornsilk\" color=\"rgb(255,248,220)\" compliance=\"SVG, X11, XPM\" />"
107     "  <color name=\"crimson\" color=\"rgb(220,20,60)\" compliance=\"SVG\" />"
108     "  <color name=\"DarkBlue\" color=\"rgb(0,0,139)\" compliance=\"SVG, X11\" />"
109     "  <color name=\"DarkCyan\" color=\"rgb(0,139,139)\" compliance=\"SVG, X11\" />"
110     "  <color name=\"DarkGoldenrod\" color=\"rgb(184,134,11)\" compliance=\"SVG, X11, XPM\" />"
111     "  <color name=\"DarkGray\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
112     "  <color name=\"DarkGreen\" color=\"rgb(0,100,0)\" compliance=\"SVG, X11, XPM\" />"
113     "  <color name=\"DarkGrey\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
114     "  <color name=\"DarkKhaki\" color=\"rgb(189,183,107)\" compliance=\"SVG, X11, XPM\" />"
115     "  <color name=\"DarkMagenta\" color=\"rgb(139,0,139)\" compliance=\"SVG, X11\" />"
116     "  <color name=\"DarkOliveGreen\" color=\"rgb(85,107,47)\" compliance=\"SVG, X11, XPM\" />"
117     "  <color name=\"DarkOrange\" color=\"rgb(255,140,0)\" compliance=\"SVG, X11, XPM\" />"
118     "  <color name=\"DarkOrchid\" color=\"rgb(153,50,204)\" compliance=\"SVG, X11, XPM\" />"
119     "  <color name=\"DarkRed\" color=\"rgb(139,0,0)\" compliance=\"SVG, X11\" />"
120     "  <color name=\"DarkSalmon\" color=\"rgb(233,150,122)\" compliance=\"SVG, X11, XPM\" />"
121     "  <color name=\"DarkSeaGreen\" color=\"rgb(143,188,143)\" compliance=\"SVG, X11, XPM\" />"
122     "  <color name=\"DarkSlateBlue\" color=\"rgb(72,61,139)\" compliance=\"SVG, X11, XPM\" />"
123     "  <color name=\"DarkSlateGray\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11, XPM\" />"
124     "  <color name=\"DarkSlateGrey\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11\" />"
125     "  <color name=\"DarkTurquoise\" color=\"rgb(0,206,209)\" compliance=\"SVG, X11, XPM\" />"
126     "  <color name=\"DarkViolet\" color=\"rgb(148,0,211)\" compliance=\"SVG, X11, XPM\" />"
127     "  <color name=\"DeepPink\" color=\"rgb(255,20,147)\" compliance=\"SVG, X11, XPM\" />"
128     "  <color name=\"DeepSkyBlue\" color=\"rgb(0,191,255)\" compliance=\"SVG, X11, XPM\" />"
129     "  <color name=\"DimGray\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11, XPM\" />"
130     "  <color name=\"DimGrey\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
131     "  <color name=\"DodgerBlue\" color=\"rgb(30,144,255)\" compliance=\"SVG, X11, XPM\" />"
132     "  <color name=\"firebrick\" color=\"rgb(178,34,34)\" compliance=\"SVG, X11, XPM\" />"
133     "  <color name=\"FloralWhite\" color=\"rgb(255,250,240)\" compliance=\"SVG, X11, XPM\" />"
134     "  <color name=\"ForestGreen\" color=\"rgb(34,139,34)\" compliance=\"SVG, X11, XPM\" />"
135     "  <color name=\"fractal\" color=\"rgb(128,128,128)\" compliance=\"SVG\" />"
136     "  <color name=\"fuchsia\" color=\"rgb(255,0,255)\" compliance=\"SVG\" />"
137     "  <color name=\"gainsboro\" color=\"rgb(220,220,220)\" compliance=\"SVG, X11, XPM\" />"
138     "  <color name=\"GhostWhite\" color=\"rgb(248,248,255)\" compliance=\"SVG, X11, XPM\" />"
139     "  <color name=\"gold\" color=\"rgb(255,215,0)\" compliance=\"X11, XPM\" />"
140     "  <color name=\"goldenrod\" color=\"rgb(218,165,32)\" compliance=\"SVG, X11, XPM\" />"
141     "  <color name=\"gray\" color=\"rgb(126,126,126)\" compliance=\"SVG\" />"
142     "  <color name=\"gray74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
143     "  <color name=\"gray100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
144     "  <color name=\"grey\" color=\"rgb(190,190,190)\" compliance=\"SVG, X11\" />"
145     "  <color name=\"grey0\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11\" />"
146     "  <color name=\"grey1\" color=\"rgb(3,3,3)\" compliance=\"SVG, X11\" />"
147     "  <color name=\"grey10\" color=\"rgb(26,26,26)\" compliance=\"SVG, X11\" />"
148     "  <color name=\"grey100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
149     "  <color name=\"grey11\" color=\"rgb(28,28,28)\" compliance=\"SVG, X11\" />"
150     "  <color name=\"grey12\" color=\"rgb(31,31,31)\" compliance=\"SVG, X11\" />"
151     "  <color name=\"grey13\" color=\"rgb(33,33,33)\" compliance=\"SVG, X11\" />"
152     "  <color name=\"grey14\" color=\"rgb(36,36,36)\" compliance=\"SVG, X11\" />"
153     "  <color name=\"grey15\" color=\"rgb(38,38,38)\" compliance=\"SVG, X11\" />"
154     "  <color name=\"grey16\" color=\"rgb(41,41,41)\" compliance=\"SVG, X11\" />"
155     "  <color name=\"grey17\" color=\"rgb(43,43,43)\" compliance=\"SVG, X11\" />"
156     "  <color name=\"grey18\" color=\"rgb(45,45,45)\" compliance=\"SVG, X11\" />"
157     "  <color name=\"grey19\" color=\"rgb(48,48,48)\" compliance=\"SVG, X11\" />"
158     "  <color name=\"grey2\" color=\"rgb(5,5,5)\" compliance=\"SVG, X11\" />"
159     "  <color name=\"grey20\" color=\"rgb(51,51,51)\" compliance=\"SVG, X11\" />"
160     "  <color name=\"grey21\" color=\"rgb(54,54,54)\" compliance=\"SVG, X11\" />"
161     "  <color name=\"grey22\" color=\"rgb(56,56,56)\" compliance=\"SVG, X11\" />"
162     "  <color name=\"grey23\" color=\"rgb(59,59,59)\" compliance=\"SVG, X11\" />"
163     "  <color name=\"grey24\" color=\"rgb(61,61,61)\" compliance=\"SVG, X11\" />"
164     "  <color name=\"grey25\" color=\"rgb(64,64,64)\" compliance=\"SVG, X11\" />"
165     "  <color name=\"grey26\" color=\"rgb(66,66,66)\" compliance=\"SVG, X11\" />"
166     "  <color name=\"grey27\" color=\"rgb(69,69,69)\" compliance=\"SVG, X11\" />"
167     "  <color name=\"grey28\" color=\"rgb(71,71,71)\" compliance=\"SVG, X11\" />"
168     "  <color name=\"grey29\" color=\"rgb(74,74,74)\" compliance=\"SVG, X11\" />"
169     "  <color name=\"grey3\" color=\"rgb(8,8,8)\" compliance=\"SVG, X11\" />"
170     "  <color name=\"grey30\" color=\"rgb(77,77,77)\" compliance=\"SVG, X11\" />"
171     "  <color name=\"grey31\" color=\"rgb(79,79,79)\" compliance=\"SVG, X11\" />"
172     "  <color name=\"grey32\" color=\"rgb(82,82,82)\" compliance=\"SVG, X11\" />"
173     "  <color name=\"grey33\" color=\"rgb(84,84,84)\" compliance=\"SVG, X11\" />"
174     "  <color name=\"grey34\" color=\"rgb(87,87,87)\" compliance=\"SVG, X11\" />"
175     "  <color name=\"grey35\" color=\"rgb(89,89,89)\" compliance=\"SVG, X11\" />"
176     "  <color name=\"grey36\" color=\"rgb(92,92,92)\" compliance=\"SVG, X11\" />"
177     "  <color name=\"grey37\" color=\"rgb(94,94,94)\" compliance=\"SVG, X11\" />"
178     "  <color name=\"grey38\" color=\"rgb(97,97,97)\" compliance=\"SVG, X11\" />"
179     "  <color name=\"grey39\" color=\"rgb(99,99,99)\" compliance=\"SVG, X11\" />"
180     "  <color name=\"grey4\" color=\"rgb(10,10,10)\" compliance=\"SVG, X11\" />"
181     "  <color name=\"grey40\" color=\"rgb(102,102,102)\" compliance=\"SVG, X11\" />"
182     "  <color name=\"grey41\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
183     "  <color name=\"grey42\" color=\"rgb(107,107,107)\" compliance=\"SVG, X11\" />"
184     "  <color name=\"grey43\" color=\"rgb(110,110,110)\" compliance=\"SVG, X11\" />"
185     "  <color name=\"grey44\" color=\"rgb(112,112,112)\" compliance=\"SVG, X11\" />"
186     "  <color name=\"grey45\" color=\"rgb(115,115,115)\" compliance=\"SVG, X11\" />"
187     "  <color name=\"grey45\" color=\"rgb(117,117,117)\" compliance=\"SVG, X11\" />"
188     "  <color name=\"grey47\" color=\"rgb(120,120,120)\" compliance=\"SVG, X11\" />"
189     "  <color name=\"grey48\" color=\"rgb(122,122,122)\" compliance=\"SVG, X11\" />"
190     "  <color name=\"grey49\" color=\"rgb(125,125,125)\" compliance=\"SVG, X11\" />"
191     "  <color name=\"grey5\" color=\"rgb(13,13,13)\" compliance=\"SVG, X11\" />"
192     "  <color name=\"grey50\" color=\"rgb(50%,50%,50%)\" compliance=\"SVG, X11\" />"
193     "  <color name=\"grey51\" color=\"rgb(130,130,130)\" compliance=\"SVG, X11\" />"
194     "  <color name=\"grey52\" color=\"rgb(133,133,133)\" compliance=\"SVG, X11\" />"
195     "  <color name=\"grey53\" color=\"rgb(135,135,135)\" compliance=\"SVG, X11\" />"
196     "  <color name=\"grey54\" color=\"rgb(138,138,138)\" compliance=\"SVG, X11\" />"
197     "  <color name=\"grey55\" color=\"rgb(140,140,140)\" compliance=\"SVG, X11\" />"
198     "  <color name=\"grey56\" color=\"rgb(143,143,143)\" compliance=\"SVG, X11\" />"
199     "  <color name=\"grey57\" color=\"rgb(145,145,145)\" compliance=\"SVG, X11\" />"
200     "  <color name=\"grey58\" color=\"rgb(148,148,148)\" compliance=\"SVG, X11\" />"
201     "  <color name=\"grey59\" color=\"rgb(150,150,150)\" compliance=\"SVG, X11\" />"
202     "  <color name=\"grey6\" color=\"rgb(15,15,15)\" compliance=\"SVG, X11\" />"
203     "  <color name=\"grey60\" color=\"rgb(153,153,153)\" compliance=\"SVG, X11\" />"
204     "  <color name=\"grey61\" color=\"rgb(156,156,156)\" compliance=\"SVG, X11\" />"
205     "  <color name=\"grey62\" color=\"rgb(158,158,158)\" compliance=\"SVG, X11\" />"
206     "  <color name=\"grey63\" color=\"rgb(161,161,161)\" compliance=\"SVG, X11\" />"
207     "  <color name=\"grey64\" color=\"rgb(163,163,163)\" compliance=\"SVG, X11\" />"
208     "  <color name=\"grey65\" color=\"rgb(166,166,166)\" compliance=\"SVG, X11\" />"
209     "  <color name=\"grey66\" color=\"rgb(168,168,168)\" compliance=\"SVG, X11\" />"
210     "  <color name=\"grey67\" color=\"rgb(171,171,171)\" compliance=\"SVG, X11\" />"
211     "  <color name=\"grey68\" color=\"rgb(173,173,173)\" compliance=\"SVG, X11\" />"
212     "  <color name=\"grey69\" color=\"rgb(176,176,176)\" compliance=\"SVG, X11\" />"
213     "  <color name=\"grey7\" color=\"rgb(18,18,18)\" compliance=\"SVG, X11\" />"
214     "  <color name=\"grey70\" color=\"rgb(179,179,179)\" compliance=\"SVG, X11\" />"
215     "  <color name=\"grey71\" color=\"rgb(181,181,181)\" compliance=\"SVG, X11\" />"
216     "  <color name=\"grey72\" color=\"rgb(184,184,184)\" compliance=\"SVG, X11\" />"
217     "  <color name=\"grey73\" color=\"rgb(186,186,186)\" compliance=\"SVG, X11\" />"
218     "  <color name=\"grey74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
219     "  <color name=\"grey75\" color=\"rgb(191,191,191)\" compliance=\"SVG, X11\" />"
220     "  <color name=\"grey76\" color=\"rgb(194,194,194)\" compliance=\"SVG, X11\" />"
221     "  <color name=\"grey77\" color=\"rgb(196,196,196)\" compliance=\"SVG, X11\" />"
222     "  <color name=\"grey78\" color=\"rgb(199,199,199)\" compliance=\"SVG, X11\" />"
223     "  <color name=\"grey79\" color=\"rgb(201,201,201)\" compliance=\"SVG, X11\" />"
224     "  <color name=\"grey8\" color=\"rgb(20,20,20)\" compliance=\"SVG, X11\" />"
225     "  <color name=\"grey80\" color=\"rgb(204,204,204)\" compliance=\"SVG, X11\" />"
226     "  <color name=\"grey81\" color=\"rgb(207,207,207)\" compliance=\"SVG, X11\" />"
227     "  <color name=\"grey82\" color=\"rgb(209,209,209)\" compliance=\"SVG, X11\" />"
228     "  <color name=\"grey83\" color=\"rgb(212,212,212)\" compliance=\"SVG, X11\" />"
229     "  <color name=\"grey84\" color=\"rgb(214,214,214)\" compliance=\"SVG, X11\" />"
230     "  <color name=\"grey85\" color=\"rgb(217,217,217)\" compliance=\"SVG, X11\" />"
231     "  <color name=\"grey86\" color=\"rgb(219,219,219)\" compliance=\"SVG, X11\" />"
232     "  <color name=\"grey87\" color=\"rgb(222,222,222)\" compliance=\"SVG, X11\" />"
233     "  <color name=\"grey88\" color=\"rgb(224,224,224)\" compliance=\"SVG, X11\" />"
234     "  <color name=\"grey89\" color=\"rgb(227,227,227)\" compliance=\"SVG, X11\" />"
235     "  <color name=\"grey9\" color=\"rgb(23,23,23)\" compliance=\"SVG, X11\" />"
236     "  <color name=\"grey90\" color=\"rgb(229,229,229)\" compliance=\"SVG, X11\" />"
237     "  <color name=\"grey91\" color=\"rgb(232,232,232)\" compliance=\"SVG, X11\" />"
238     "  <color name=\"grey92\" color=\"rgb(235,235,235)\" compliance=\"SVG, X11\" />"
239     "  <color name=\"grey93\" color=\"rgb(237,237,237)\" compliance=\"SVG, X11\" />"
240     "  <color name=\"grey94\" color=\"rgb(240,240,240)\" compliance=\"SVG, X11\" />"
241     "  <color name=\"grey95\" color=\"rgb(242,242,242)\" compliance=\"SVG, X11\" />"
242     "  <color name=\"grey96\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11\" />"
243     "  <color name=\"grey97\" color=\"rgb(247,247,247)\" compliance=\"SVG, X11\" />"
244     "  <color name=\"grey98\" color=\"rgb(250,250,250)\" compliance=\"SVG, X11\" />"
245     "  <color name=\"grey99\" color=\"rgb(252,252,252)\" compliance=\"SVG, X11\" />"
246     "  <color name=\"honeydew\" color=\"rgb(240,255,240)\" compliance=\"SVG, X11, XPM\" />"
247     "  <color name=\"HotPink\" color=\"rgb(255,105,180)\" compliance=\"SVG, X11, XPM\" />"
248     "  <color name=\"IndianRed\" color=\"rgb(205,92,92)\" compliance=\"SVG, X11, XPM\" />"
249     "  <color name=\"indigo\" color=\"rgb(75,0,130)\" compliance=\"SVG\" />"
250     "  <color name=\"ivory\" color=\"rgb(255,255,240)\" compliance=\"SVG, X11, XPM\" />"
251     "  <color name=\"khaki\" color=\"rgb(240,230,140)\" compliance=\"SVG, X11, XPM\" />"
252     "  <color name=\"lavender\" color=\"rgb(230,230,250)\" compliance=\"SVG, X11, XPM\" />"
253     "  <color name=\"LavenderBlush\" color=\"rgb(255,240,245)\" compliance=\"SVG, X11, XPM\" />"
254     "  <color name=\"LawnGreen\" color=\"rgb(124,252,0)\" compliance=\"SVG, X11, XPM\" />"
255     "  <color name=\"LemonChiffon\" color=\"rgb(255,250,205)\" compliance=\"SVG, X11, XPM\" />"
256     "  <color name=\"LightBlue\" color=\"rgb(173,216,230)\" compliance=\"SVG, X11, XPM\" />"
257     "  <color name=\"LightCoral\" color=\"rgb(240,128,128)\" compliance=\"SVG, X11, XPM\" />"
258     "  <color name=\"LightCyan\" color=\"rgb(224,255,255)\" compliance=\"SVG, X11, XPM\" />"
259     "  <color name=\"LightGoldenrodYellow\" color=\"rgb(250,250,210)\" compliance=\"SVG, X11, XPM\" />"
260     "  <color name=\"LightGray\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11, XPM\" />"
261     "  <color name=\"LightGreen\" color=\"rgb(144,238,144)\" compliance=\"SVG, X11\" />"
262     "  <color name=\"LightGrey\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11\" />"
263     "  <color name=\"LightPink\" color=\"rgb(255,182,193)\" compliance=\"SVG, X11, XPM\" />"
264     "  <color name=\"LightSalmon\" color=\"rgb(255,160,122)\" compliance=\"SVG, X11, XPM\" />"
265     "  <color name=\"LightSeaGreen\" color=\"rgb(32,178,170)\" compliance=\"SVG, X11, XPM\" />"
266     "  <color name=\"LightSkyBlue\" color=\"rgb(135,206,250)\" compliance=\"SVG, X11, XPM\" />"
267     "  <color name=\"LightSlateGray\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11, XPM\" />"
268     "  <color name=\"LightSlateGrey\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11\" />"
269     "  <color name=\"LightSteelBlue\" color=\"rgb(176,196,222)\" compliance=\"SVG, X11, XPM\" />"
270     "  <color name=\"LightYellow\" color=\"rgb(255,255,224)\" compliance=\"SVG, X11, XPM\" />"
271     "  <color name=\"lime\" color=\"rgb(0,255,0)\" compliance=\"SVG\" />"
272     "  <color name=\"LimeGreen\" color=\"rgb(50,205,50)\" compliance=\"SVG, X11, XPM\" />"
273     "  <color name=\"linen\" color=\"rgb(250,240,230)\" compliance=\"SVG, X11, XPM\" />"
274     "  <color name=\"maroon\" color=\"rgb(128,0,0)\" compliance=\"SVG\" />"
275     "  <color name=\"MediumAquamarine\" color=\"rgb(102,205,170)\" compliance=\"SVG, X11, XPM\" />"
276     "  <color name=\"MediumBlue\" color=\"rgb(0,0,205)\" compliance=\"SVG, X11, XPM\" />"
277     "  <color name=\"MediumOrchid\" color=\"rgb(186,85,211)\" compliance=\"SVG, X11, XPM\" />"
278     "  <color name=\"MediumPurple\" color=\"rgb(147,112,219)\" compliance=\"SVG, X11, XPM\" />"
279     "  <color name=\"MediumSeaGreen\" color=\"rgb(60,179,113)\" compliance=\"SVG, X11, XPM\" />"
280     "  <color name=\"MediumSlateBlue\" color=\"rgb(123,104,238)\" compliance=\"SVG, X11, XPM\" />"
281     "  <color name=\"MediumSpringGreen\" color=\"rgb(0,250,154)\" compliance=\"SVG, X11, XPM\" />"
282     "  <color name=\"MediumTurquoise\" color=\"rgb(72,209,204)\" compliance=\"SVG, X11, XPM\" />"
283     "  <color name=\"MediumVioletRed\" color=\"rgb(199,21,133)\" compliance=\"SVG, X11, XPM\" />"
284     "  <color name=\"MidnightBlue\" color=\"rgb(25,25,112)\" compliance=\"SVG, X11, XPM\" />"
285     "  <color name=\"MintCream\" color=\"rgb(245,255,250)\" compliance=\"SVG, X11, XPM\" />"
286     "  <color name=\"MistyRose\" color=\"rgb(255,228,225)\" compliance=\"SVG, X11, XPM\" />"
287     "  <color name=\"moccasin\" color=\"rgb(255,228,181)\" compliance=\"SVG, X11, XPM\" />"
288     "  <color name=\"NavajoWhite\" color=\"rgb(255,222,173)\" compliance=\"SVG, X11, XPM\" />"
289     "  <color name=\"navy\" color=\"rgb(0,0,128)\" compliance=\"SVG, X11, XPM\" />"
290     "  <color name=\"matte\" color=\"rgb(0,0,0,0)\" compliance=\"SVG\" />"
291     "  <color name=\"OldLace\" color=\"rgb(253,245,230)\" compliance=\"SVG, X11, XPM\" />"
292     "  <color name=\"olive\" color=\"rgb(128,128,0)\" compliance=\"SVG\" />"
293     "  <color name=\"OliveDrab\" color=\"rgb(107,142,35)\" compliance=\"SVG, X11, XPM\" />"
294     "  <color name=\"opaque\" color=\"rgb(0,0,0)\" compliance=\"SVG\" />"
295     "  <color name=\"orange\" color=\"rgb(255,165,0)\" compliance=\"SVG, X11, XPM\" />"
296     "  <color name=\"OrangeRed\" color=\"rgb(255,69,0)\" compliance=\"SVG, X11, XPM\" />"
297     "  <color name=\"orchid\" color=\"rgb(218,112,214)\" compliance=\"SVG, X11, XPM\" />"
298     "  <color name=\"PaleGoldenrod\" color=\"rgb(238,232,170)\" compliance=\"SVG, X11, XPM\" />"
299     "  <color name=\"PaleGreen\" color=\"rgb(152,251,152)\" compliance=\"SVG, X11, XPM\" />"
300     "  <color name=\"PaleTurquoise\" color=\"rgb(175,238,238)\" compliance=\"SVG, X11, XPM\" />"
301     "  <color name=\"PaleVioletRed\" color=\"rgb(219,112,147)\" compliance=\"SVG, X11, XPM\" />"
302     "  <color name=\"PapayaWhip\" color=\"rgb(255,239,213)\" compliance=\"SVG, X11, XPM\" />"
303     "  <color name=\"PeachPuff\" color=\"rgb(255,218,185)\" compliance=\"SVG, X11, XPM\" />"
304     "  <color name=\"peru\" color=\"rgb(205,133,63)\" compliance=\"SVG, X11, XPM\" />"
305     "  <color name=\"pink\" color=\"rgb(255,192,203)\" compliance=\"SVG, X11, XPM\" />"
306     "  <color name=\"plum\" color=\"rgb(221,160,221)\" compliance=\"SVG, X11, XPM\" />"
307     "  <color name=\"PowderBlue\" color=\"rgb(176,224,230)\" compliance=\"SVG, X11, XPM\" />"
308     "  <color name=\"purple\" color=\"rgb(128,0,128)\" compliance=\"SVG\" />"
309     "  <color name=\"RosyBrown\" color=\"rgb(188,143,143)\" compliance=\"SVG, X11, XPM\" />"
310     "  <color name=\"RoyalBlue\" color=\"rgb(65,105,225)\" compliance=\"SVG, X11, XPM\" />"
311     "  <color name=\"SaddleBrown\" color=\"rgb(139,69,19)\" compliance=\"SVG, X11, XPM\" />"
312     "  <color name=\"salmon\" color=\"rgb(250,128,114)\" compliance=\"SVG, X11, XPM\" />"
313     "  <color name=\"SandyBrown\" color=\"rgb(244,164,96)\" compliance=\"SVG, X11, XPM\" />"
314     "  <color name=\"SeaGreen\" color=\"rgb(45,139,87)\" compliance=\"SVG, X11, XPM\" />"
315     "  <color name=\"seashell\" color=\"rgb(255,245,238)\" compliance=\"SVG, X11, XPM\" />"
316     "  <color name=\"sienna\" color=\"rgb(160,82,45)\" compliance=\"SVG, X11, XPM\" />"
317     "  <color name=\"silver\" color=\"rgb(192,192,192)\" compliance=\"SVG\" />"
318     "  <color name=\"SkyBlue\" color=\"rgb(135,206,235)\" compliance=\"SVG, X11, XPM\" />"
319     "  <color name=\"SlateBlue\" color=\"rgb(106,90,205)\" compliance=\"SVG, X11, XPM\" />"
320     "  <color name=\"SlateGray\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11, XPM\" />"
321     "  <color name=\"SlateGrey\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11\" />"
322     "  <color name=\"snow\" color=\"rgb(255,250,250)\" compliance=\"SVG, X11, XPM\" />"
323     "  <color name=\"SpringGreen\" color=\"rgb(0,255,127)\" compliance=\"SVG, X11, XPM\" />"
324     "  <color name=\"SteelBlue\" color=\"rgb(70,130,180)\" compliance=\"SVG, X11, XPM\" />"
325     "  <color name=\"tan\" color=\"rgb(210,180,140)\" compliance=\"SVG, X11, XPM\" />"
326     "  <color name=\"teal\" color=\"rgb(0,128,128)\" compliance=\"SVG\" />"
327     "  <color name=\"thistle\" color=\"rgb(216,191,216)\" compliance=\"SVG, X11, XPM\" />"
328     "  <color name=\"tomato\" color=\"rgb(255,99,71)\" compliance=\"SVG, X11, XPM\" />"
329     "  <color name=\"transparent\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
330     "  <color name=\"turquoise\" color=\"rgb(64,224,208)\" compliance=\"SVG, X11, XPM\" />"
331     "  <color name=\"violet\" color=\"rgb(238,130,238)\" compliance=\"SVG, X11, XPM\" />"
332     "  <color name=\"wheat\" color=\"rgb(245,222,179)\" compliance=\"SVG, X11, XPM\" />"
333     "  <color name=\"WhiteSmoke\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11, XPM\" />"
334     "  <color name=\"YellowGreen\" color=\"rgb(154,205,50)\" compliance=\"SVG, X11, XPM\" />"
335     "</colormap>";
336 \f
337 /*
338   Static declarations.
339 */
340 static LinkedListInfo
341   *color_list = (LinkedListInfo *) NULL;
342
343 static SemaphoreInfo
344   *color_semaphore = (SemaphoreInfo *) NULL;
345
346 static volatile MagickBooleanType
347   instantiate_color = MagickFalse;
348 \f
349 /*
350   Forward declarations.
351 */
352 static MagickBooleanType
353   InitializeColorList(ExceptionInfo *),
354   LoadColorLists(const char *,ExceptionInfo *);
355 \f
356 /*
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 %                                                                             %
359 %                                                                             %
360 %                                                                             %
361 +   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                         %
362 %                                                                             %
363 %                                                                             %
364 %                                                                             %
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 %
367 %  ConcatenateColorComponent() returns the pixel as a canonical string.
368 %
369 %  The format of the ConcatenateColorComponent() method is:
370 %
371 %      void ConcatenateColorComponent(const MagickPixelPacket *pixel,
372 %        const ChannelType channel,const ComplianceType compliance,char *tuple)
373 %
374 %  A description of each parameter follows.
375 %
376 %    o pixel:  The pixel.
377 %
378 %    channel:  The channel.
379 %
380 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
381 %
382 %    tuple:  The color tuple.
383 %
384 */
385 MagickExport void ConcatenateColorComponent(const MagickPixelPacket *pixel,
386   const ChannelType channel,const ComplianceType compliance,char *tuple)
387 {
388   char
389     component[MaxTextExtent];
390
391   MagickRealType
392     color;
393
394   color=0.0;
395   switch (channel)
396   {
397     case RedChannel:
398     {
399       color=pixel->red;
400       break;
401     }
402     case GreenChannel:
403     {
404       color=pixel->green;
405       break;
406     }
407     case BlueChannel:
408     {
409       color=pixel->blue;
410       break;
411     }
412     case AlphaChannel:
413     {
414       color=QuantumRange-pixel->opacity;
415       break;
416     }
417     case IndexChannel:
418     {
419       color=pixel->index;
420       break;
421     }
422     default:
423       break;
424   }
425   if (compliance != SVGCompliance)
426     {
427       if (pixel->depth > 16)
428         {
429           (void) FormatMagickString(component,MaxTextExtent,"%10lu",
430             (unsigned long) ScaleQuantumToLong(RoundToQuantum(color)));
431           (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
432           return;
433         }
434       if (pixel->depth > 8)
435         {
436           (void) FormatMagickString(component,MaxTextExtent,"%5d",
437             ScaleQuantumToShort(RoundToQuantum(color)));
438           (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
439           return;
440         }
441       (void) FormatMagickString(component,MaxTextExtent,"%3d",
442         ScaleQuantumToChar(RoundToQuantum(color)));
443       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
444       return;
445     }
446   if (channel == OpacityChannel)
447     {
448       (void) FormatMagickString(component,MaxTextExtent,"%g",
449         (double) (QuantumScale*color));
450       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
451       return;
452     }
453   if (pixel->depth > 8)
454     {
455       (void) FormatMagickString(component,MaxTextExtent,"%g%%",
456         (double) (100.0*QuantumScale*color));
457       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
458       return;
459     }
460   (void) FormatMagickString(component,MaxTextExtent,"%d",
461     ScaleQuantumToChar(RoundToQuantum(color)));
462   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
463 }
464 \f
465 /*
466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 %                                                                             %
468 %                                                                             %
469 %                                                                             %
470 +   D e s t r o y C o l o r L i s t                                           %
471 %                                                                             %
472 %                                                                             %
473 %                                                                             %
474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475 %
476 %  DestroyColorList() deallocates memory associated with the color list.
477 %
478 %  The format of the DestroyColorList method is:
479 %
480 %      DestroyColorList(void)
481 %
482 */
483
484 static void *DestroyColorElement(void *color_info)
485 {
486   register ColorInfo
487     *p;
488
489   p=(ColorInfo *) color_info;
490   if (p->path != (char *) NULL)
491     p->path=DestroyString(p->path);
492   if (p->name != (char *) NULL)
493     p->name=DestroyString(p->name);
494   p=(ColorInfo *) RelinquishMagickMemory(p);
495   return((void *) NULL);
496 }
497
498 MagickExport void DestroyColorList(void)
499 {
500   AcquireSemaphoreInfo(&color_semaphore);
501   if (color_list != (LinkedListInfo *) NULL)
502     color_list=DestroyLinkedList(color_list,DestroyColorElement);
503   instantiate_color=MagickFalse;
504   RelinquishSemaphoreInfo(color_semaphore);
505   DestroySemaphoreInfo(&color_semaphore);
506 }
507 \f
508 /*
509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510 %                                                                             %
511 %                                                                             %
512 %                                                                             %
513 +   G e t C o l o r I n f o                                                   %
514 %                                                                             %
515 %                                                                             %
516 %                                                                             %
517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 %
519 %  GetColorInfo() searches the color list for the specified name and if found
520 %  returns attributes for that color.
521 %
522 %  The format of the GetColorInfo method is:
523 %
524 %      const PixelPacket *GetColorInfo(const char *name,
525 %        ExceptionInfo *exception)
526 %
527 %  A description of each parameter follows:
528 %
529 %    o color_info: search the color list for the specified name and if found
530 %      return attributes for that color.
531 %
532 %    o name: the color name.
533 %
534 %    o exception: return any errors or warnings in this structure.
535 %
536 */
537 MagickExport const ColorInfo *GetColorInfo(const char *name,
538   ExceptionInfo *exception)
539 {
540   char
541     colorname[MaxTextExtent];
542
543   register const ColorInfo
544     *p;
545
546   register char
547     *q;
548
549   assert(exception != (ExceptionInfo *) NULL);
550   if ((color_list == (LinkedListInfo *) NULL) ||
551       (instantiate_color == MagickFalse))
552     if (InitializeColorList(exception) == MagickFalse)
553       return((const ColorInfo *) NULL);
554   if ((color_list == (LinkedListInfo *) NULL) ||
555       (IsLinkedListEmpty(color_list) != MagickFalse))
556     return((const ColorInfo *) NULL);
557   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
558     return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
559   /*
560     Strip names of whitespace.
561   */
562   (void) CopyMagickString(colorname,name,MaxTextExtent);
563   for (q=colorname; *q != '\0'; q++)
564   {
565     if (isspace((int) ((unsigned char) *q)) == 0)
566       continue;
567     (void) CopyMagickString(q,q+1,MaxTextExtent);
568     q--;
569   }
570   /*
571     Search for color tag.
572   */
573   AcquireSemaphoreInfo(&color_semaphore);
574   ResetLinkedListIterator(color_list);
575   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
576   while (p != (const ColorInfo *) NULL)
577   {
578     if (LocaleCompare(colorname,p->name) == 0)
579       break;
580     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
581   }
582   if (p == (ColorInfo *) NULL)
583     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
584       "UnrecognizedColor","`%s'",name);
585   else
586     (void) InsertValueInLinkedList(color_list,0,
587       RemoveElementByValueFromLinkedList(color_list,p));
588   RelinquishSemaphoreInfo(color_semaphore);
589   return(p);
590 }
591 \f
592 /*
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594 %                                                                             %
595 %                                                                             %
596 %                                                                             %
597 %   G e t C o l o r I n f o L i s t                                           %
598 %                                                                             %
599 %                                                                             %
600 %                                                                             %
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 %
603 %  GetColorInfoList() returns any colors that match the specified pattern.
604 %
605 %  The format of the GetColorInfoList function is:
606 %
607 %      const ColorInfo **GetColorInfoList(const char *pattern,
608 %        unsigned long *number_colors,ExceptionInfo *exception)
609 %
610 %  A description of each parameter follows:
611 %
612 %    o pattern: Specifies a pointer to a text string containing a pattern.
613 %
614 %    o number_colors:  This integer returns the number of colors in the list.
615 %
616 %    o exception: return any errors or warnings in this structure.
617 %
618 */
619
620 #if defined(__cplusplus) || defined(c_plusplus)
621 extern "C" {
622 #endif
623
624 static int ColorInfoCompare(const void *x,const void *y)
625 {
626   const ColorInfo
627     **p,
628     **q;
629
630   p=(const ColorInfo **) x,
631   q=(const ColorInfo **) y;
632   if (LocaleCompare((*p)->path,(*q)->path) == 0)
633     return(LocaleCompare((*p)->name,(*q)->name));
634   return(LocaleCompare((*p)->path,(*q)->path));
635 }
636
637 #if defined(__cplusplus) || defined(c_plusplus)
638 }
639 #endif
640
641 MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
642   unsigned long *number_colors,ExceptionInfo *exception)
643 {
644   const ColorInfo
645     **colors;
646
647   register const ColorInfo
648     *p;
649
650   register long
651     i;
652
653   /*
654     Allocate color list.
655   */
656   assert(pattern != (char *) NULL);
657   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
658   assert(number_colors != (unsigned long *) NULL);
659   *number_colors=0;
660   p=GetColorInfo("*",exception);
661   if (p == (const ColorInfo *) NULL)
662     return((const ColorInfo **) NULL);
663   colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
664     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
665   if (colors == (const ColorInfo **) NULL)
666     return((const ColorInfo **) NULL);
667   /*
668     Generate color list.
669   */
670   AcquireSemaphoreInfo(&color_semaphore);
671   ResetLinkedListIterator(color_list);
672   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
673   for (i=0; p != (const ColorInfo *) NULL; )
674   {
675     if ((p->stealth == MagickFalse) &&
676         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
677       colors[i++]=p;
678     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
679   }
680   RelinquishSemaphoreInfo(color_semaphore);
681   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
682   colors[i]=(ColorInfo *) NULL;
683   *number_colors=(unsigned long) i;
684   return(colors);
685 }
686 \f
687 /*
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 %   G e t C o l o r L i s t                                                   %
693 %                                                                             %
694 %                                                                             %
695 %                                                                             %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %
698 %  GetColorList() returns any colors that match the specified pattern.
699 %
700 %  The format of the GetColorList function is:
701 %
702 %      char **GetColorList(const char *pattern,unsigned long *number_colors,
703 %        ExceptionInfo *exception)
704 %
705 %  A description of each parameter follows:
706 %
707 %    o pattern: Specifies a pointer to a text string containing a pattern.
708 %
709 %    o number_colors:  This integer returns the number of colors in the list.
710 %
711 %    o exception: return any errors or warnings in this structure.
712 %
713 */
714
715 #if defined(__cplusplus) || defined(c_plusplus)
716 extern "C" {
717 #endif
718
719 static int ColorCompare(const void *x,const void *y)
720 {
721   register const char
722     **p,
723     **q;
724
725   p=(const char **) x;
726   q=(const char **) y;
727   return(LocaleCompare(*p,*q));
728 }
729
730 #if defined(__cplusplus) || defined(c_plusplus)
731 }
732 #endif
733
734 MagickExport char **GetColorList(const char *pattern,
735   unsigned long *number_colors,ExceptionInfo *exception)
736 {
737   char
738     **colors;
739
740   register const ColorInfo
741     *p;
742
743   register long
744     i;
745
746   /*
747     Allocate color list.
748   */
749   assert(pattern != (char *) NULL);
750   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
751   assert(number_colors != (unsigned long *) NULL);
752   *number_colors=0;
753   p=GetColorInfo("*",exception);
754   if (p == (const ColorInfo *) NULL)
755     return((char **) NULL);
756   colors=(char **) AcquireQuantumMemory((size_t)
757     GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
758   if (colors == (char **) NULL)
759     return((char **) NULL);
760   /*
761     Generate color list.
762   */
763   AcquireSemaphoreInfo(&color_semaphore);
764   ResetLinkedListIterator(color_list);
765   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
766   for (i=0; p != (const ColorInfo *) NULL; )
767   {
768     if ((p->stealth == MagickFalse) &&
769         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
770       colors[i++]=ConstantString(p->name);
771     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
772   }
773   RelinquishSemaphoreInfo(color_semaphore);
774   qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
775   colors[i]=(char *) NULL;
776   *number_colors=(unsigned long) i;
777   return(colors);
778 }
779 \f
780 /*
781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 %                                                                             %
783 %                                                                             %
784 %                                                                             %
785 +   G e t C o l o r T u p l e                                                 %
786 %                                                                             %
787 %                                                                             %
788 %                                                                             %
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 %
791 %  GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
792 %  or hex string (e.g. #FF0000).
793 %
794 %  The format of the GetColorTuple method is:
795 %
796 %      GetColorTuple(const MagickPixelPacket *pixel,const MagickBooleanType hex,
797 %        char *tuple)
798 %
799 %  A description of each parameter follows.
800 %
801 %    o pixel: the pixel.
802 %
803 %    o hex: A value other than zero returns the tuple in a hexidecimal format.
804 %
805 %    o tuple: Return the color tuple as this string.
806 %
807 */
808
809 static void ConcatentateHexColorComponent(const MagickPixelPacket *pixel,
810   const ChannelType channel,char *tuple)
811 {
812   char
813     component[MaxTextExtent];
814
815   MagickRealType
816     color;
817
818   color=0.0;
819   switch (channel)
820   {
821     case RedChannel:
822     {
823       color=pixel->red;
824       break;
825     }
826     case GreenChannel:
827     {
828       color=pixel->green;
829       break;
830     }
831     case BlueChannel:
832     {
833       color=pixel->blue;
834       break;
835     }
836     case OpacityChannel:
837     {
838       color=(MagickRealType) QuantumRange-pixel->opacity;
839       break;
840     }
841     case IndexChannel:
842     {
843       color=pixel->index;
844       break;
845     }
846     default:
847       break;
848   }
849   if (pixel->depth > 32)
850     {
851       (void) FormatMagickString(component,MaxTextExtent,"%08lX",
852         ScaleQuantumToLong(RoundToQuantum(color)));
853       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
854       return;
855     }
856   if (pixel->depth > 16)
857     {
858       (void) FormatMagickString(component,MaxTextExtent,"%08X",
859         (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
860       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
861       return;
862     }
863   if (pixel->depth > 8)
864     {
865       (void) FormatMagickString(component,MaxTextExtent,"%04X",
866         ScaleQuantumToShort(RoundToQuantum(color)));
867       (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
868       return;
869     }
870   (void) FormatMagickString(component,MaxTextExtent,"%02X",
871     ScaleQuantumToChar(RoundToQuantum(color)));
872   (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
873   return;
874 }
875
876 MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
877   const MagickBooleanType hex,char *tuple)
878 {
879   MagickPixelPacket
880     color;
881
882   assert(pixel != (const MagickPixelPacket *) NULL);
883   assert(tuple != (char *) NULL);
884   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
885   *tuple='\0';
886   if (hex != MagickFalse)
887     {
888       /*
889         Convert pixel to hex color.
890       */
891       (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
892       ConcatentateHexColorComponent(pixel,RedChannel,tuple);
893       ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
894       ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
895       if (pixel->colorspace == CMYKColorspace)
896         ConcatentateHexColorComponent(pixel,IndexChannel,tuple);
897       if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
898         ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
899       return;
900     }
901   /*
902     Convert pixel to rgb() or cmyk() color.
903   */
904   color=(*pixel);
905   if (color.depth > 8)
906     {
907 #define SVGCompliant(component) ((MagickRealType) \
908    ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(component))));
909
910       MagickStatusType
911         status;
912
913       /*
914         SVG requires color depths > 8 expressed as percentages.
915       */
916       status=color.red == SVGCompliant(color.red);
917       status&=color.green == SVGCompliant(color.green);
918       status&=color.blue == SVGCompliant(color.blue);
919       if (color.colorspace != CMYKColorspace)
920         status&=color.index == SVGCompliant(color.index);
921       if (color.matte != MagickFalse)
922         status&=color.opacity == SVGCompliant(color.opacity);
923       if (status != MagickFalse)
924         color.depth=8;
925     }
926   (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
927     MagickColorspaceOptions,(long) color.colorspace),MaxTextExtent);
928   if (color.matte != MagickFalse)
929     (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
930   (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
931   ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
932   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
933   ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
934   (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
935   ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
936   if (color.colorspace == CMYKColorspace)
937     {
938       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
939       ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple);
940     }
941   if (color.matte != MagickFalse)
942     {
943       (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
944       ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
945     }
946   (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
947   LocaleLower(tuple);
948   return;
949 }
950 \f
951 /*
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953 %                                                                             %
954 %                                                                             %
955 %                                                                             %
956 +   I n i t i a l i z e C o l o r L i s t                                     %
957 %                                                                             %
958 %                                                                             %
959 %                                                                             %
960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 %
962 %  InitializeColorList() initializes the color list.
963 %
964 %  The format of the InitializeColorList method is:
965 %
966 %      MagickBooleanType InitializeColorList(ExceptionInfo *exception)
967 %
968 %  A description of each parameter follows.
969 %
970 %    o exception: return any errors or warnings in this structure.
971 %
972 */
973 static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
974 {
975   if ((color_list == (LinkedListInfo *) NULL) &&
976       (instantiate_color == MagickFalse))
977     {
978       AcquireSemaphoreInfo(&color_semaphore);
979       if ((color_list == (LinkedListInfo *) NULL) &&
980           (instantiate_color == MagickFalse))
981         {
982           (void) LoadColorLists(ColorFilename,exception);
983           instantiate_color=MagickTrue;
984         }
985       RelinquishSemaphoreInfo(color_semaphore);
986     }
987   return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
988 }
989 \f
990 /*
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 %                                                                             %
993 %                                                                             %
994 %                                                                             %
995 +   I s C o l o r S i m i l a r                                               %
996 %                                                                             %
997 %                                                                             %
998 %                                                                             %
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000 %
1001 %  IsColorSimilar() returns MagickTrue if the distance between two colors is
1002 %  less than the specified distance in a linear three dimensional color space.
1003 %  This method is used by ColorFloodFill() and other algorithms which
1004 %  compare two colors.
1005 %
1006 %  The format of the IsColorSimilar method is:
1007 %
1008 %      void IsColorSimilar(const Image *image,const PixelPacket *p,
1009 %        const PixelPacket *q)
1010 %
1011 %  A description of each parameter follows:
1012 %
1013 %    o image: the image.
1014 %
1015 %    o p: Pixel p.
1016 %
1017 %    o q: Pixel q.
1018 %
1019 */
1020
1021 static inline double MagickMax(const double x,const double y)
1022 {
1023   if (x > y)
1024     return(x);
1025   return(y);
1026 }
1027
1028 MagickExport MagickBooleanType IsColorSimilar(const Image *image,
1029   const PixelPacket *p,const PixelPacket *q)
1030 {
1031   MagickRealType
1032     fuzz,
1033     pixel;
1034
1035   register MagickRealType
1036     alpha,
1037     beta,
1038     distance;
1039
1040   if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
1041     return(IsColorEqual(p,q));
1042   fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
1043     MagickSQ1_2);
1044   alpha=1.0;
1045   beta=1.0;
1046   if (image->matte != MagickFalse)
1047     {
1048       alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1049       beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1050     }
1051   pixel=alpha*p->red-beta*q->red;
1052   distance=pixel*pixel;
1053   if (distance > fuzz)
1054     return(MagickFalse);
1055   pixel=alpha*p->green-beta*q->green;
1056   distance+=pixel*pixel;
1057   if (distance > fuzz)
1058     return(MagickFalse);
1059   pixel=alpha*p->blue-beta*q->blue;
1060   distance+=pixel*pixel;
1061   if (distance > fuzz)
1062     return(MagickFalse);
1063   return(MagickTrue);
1064 }
1065 \f
1066 /*
1067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1068 %                                                                             %
1069 %                                                                             %
1070 %                                                                             %
1071 +   I s I m a g e S i m i l a r                                               %
1072 %                                                                             %
1073 %                                                                             %
1074 %                                                                             %
1075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 %
1077 %  IsImageSimilar() returns true if the target is similar to a region of the
1078 %  image.
1079 %
1080 %  The format of the IsImageSimilar method is:
1081 %
1082 %      MagickBooleanType IsImageSimilar(const Image *image,
1083 %        const Image *target_image,long *x_offset,long *y_offset,
1084 %        ExceptionInfo *exception)
1085 %
1086 %  A description of each parameter follows:
1087 %
1088 %    o image: the image.
1089 %
1090 %    o target_image: the target image.
1091 %
1092 %    o x_offset: On input the starting x position to search for a match;
1093 %      on output the x position of the first match found.
1094 %
1095 %    o y_offset: On input the starting y position to search for a match;
1096 %      on output the y position of the first match found.
1097 %
1098 %    o exception: return any errors or warnings in this structure.
1099 %
1100 */
1101 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
1102   const Image *target_image,long *x_offset,long *y_offset,
1103   ExceptionInfo *exception)
1104 {
1105 #define SearchImageText  "  Searching image...  "
1106
1107   long
1108     j,
1109     y;
1110
1111   MagickBooleanType
1112     status;
1113
1114   MagickPixelPacket
1115     target,
1116     pixel;
1117
1118   register const PixelPacket
1119     *p,
1120     *q;
1121
1122   register const IndexPacket
1123     *indexes,
1124     *target_indexes;
1125
1126   register long
1127     i,
1128     x;
1129
1130   CacheView
1131     *image_view,
1132     *target_view;
1133
1134   assert(image != (Image *) NULL);
1135   assert(image->signature == MagickSignature);
1136   if (image->debug != MagickFalse)
1137     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1138   assert(target_image != (Image *) NULL);
1139   assert(target_image->signature == MagickSignature);
1140   assert(x_offset != (long *) NULL);
1141   assert(y_offset != (long *) NULL);
1142   assert(exception != (ExceptionInfo *) NULL);
1143   x=0;
1144   GetMagickPixelPacket(image,&pixel);
1145   GetMagickPixelPacket(image,&target);
1146   image_view=AcquireCacheView(image);
1147   target_view=AcquireCacheView(target_image);
1148   for (y=(*y_offset); y < (long) image->rows; y++)
1149   {
1150     for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
1151     {
1152       for (j=0; j < (long) target_image->rows; j++)
1153       {
1154         for (i=0; i < (long) target_image->columns; i++)
1155         {
1156           p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
1157           indexes=GetCacheViewVirtualIndexQueue(image_view);
1158           SetMagickPixelPacket(image,p,indexes,&pixel);
1159           q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
1160           target_indexes=GetCacheViewVirtualIndexQueue(target_view);
1161           SetMagickPixelPacket(image,q,target_indexes,&target);
1162           if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
1163             break;
1164         }
1165         if (i < (long) target_image->columns)
1166           break;
1167       }
1168       if (j == (long) target_image->rows)
1169         break;
1170     }
1171     if (x < (long) image->columns)
1172       break;
1173     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1174         (QuantumTick(y,image->rows) != MagickFalse))
1175       {
1176         status=image->progress_monitor(SearchImageText,y,image->rows,
1177           image->client_data);
1178         if (status == MagickFalse)
1179           break;
1180       }
1181   }
1182   target_view=DestroyCacheView(target_view);
1183   image_view=DestroyCacheView(image_view);
1184   *x_offset=x;
1185   *y_offset=y;
1186   return(y < (long) image->rows ? MagickTrue : MagickFalse);
1187 }
1188 \f
1189 /*
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 %                                                                             %
1192 %                                                                             %
1193 %                                                                             %
1194 +   I s M a g i c k C o l o r S i m i l a r                                   %
1195 %                                                                             %
1196 %                                                                             %
1197 %                                                                             %
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 %
1200 %  IsMagickColorSimilar() returns true if the distance between two colors is
1201 %  less than the specified distance in a linear three dimensional color space.
1202 %  This method is used by ColorFloodFill() and other algorithms which
1203 %  compare two colors.
1204 %
1205 %  The format of the IsMagickColorSimilar method is:
1206 %
1207 %      MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
1208 %        const MagickPixelPacket *q)
1209 %
1210 %  A description of each parameter follows:
1211 %
1212 %    o p: Pixel p.
1213 %
1214 %    o q: Pixel q.
1215 %
1216 */
1217 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
1218   const MagickPixelPacket *q)
1219 {
1220   MagickRealType
1221     fuzz,
1222     pixel;
1223
1224   register MagickRealType
1225     alpha,
1226     beta,
1227     distance;
1228
1229   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
1230     return(IsMagickColorEqual(p,q));
1231   if (p->fuzz == 0.0)
1232     fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
1233   else
1234     if (q->fuzz == 0.0)
1235       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
1236     else
1237       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
1238   alpha=1.0;
1239   if (p->matte != MagickFalse)
1240     alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1241   beta=1.0;
1242   if (q->matte != MagickFalse)
1243     beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1244   if (p->colorspace == CMYKColorspace)
1245     {
1246       alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
1247       beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
1248     }
1249   pixel=alpha*p->red-beta*q->red;
1250   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
1251       (p->colorspace == HWBColorspace))
1252     {
1253       if (fabs(p->red-q->red) > (QuantumRange/2))
1254         {
1255           if (p->red > (QuantumRange/2))
1256             pixel=alpha*(p->red-QuantumRange)-beta*q->red;
1257           else
1258             pixel=alpha*p->red-beta*(q->red-QuantumRange);
1259         }
1260         pixel*=2;
1261      }
1262   distance=pixel*pixel;
1263   if (distance > fuzz)
1264     return(MagickFalse);
1265   pixel=alpha*p->green-beta*q->green;
1266   distance+=pixel*pixel;
1267   if (distance > fuzz)
1268     return(MagickFalse);
1269   pixel=alpha*p->blue-beta*q->blue;
1270   distance+=pixel*pixel;
1271   if (distance > fuzz)
1272     return(MagickFalse);
1273   pixel=p->opacity-q->opacity;
1274   distance+=pixel*pixel;
1275   if (distance > fuzz)
1276     return(MagickFalse);
1277   return(MagickTrue);
1278 }
1279 \f
1280 /*
1281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282 %                                                                             %
1283 %                                                                             %
1284 %                                                                             %
1285 +   I s O p a c i t y S i m i l a r                                           %
1286 %                                                                             %
1287 %                                                                             %
1288 %                                                                             %
1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290 %
1291 %  IsOpacitySimilar() returns true if the distance between two opacity
1292 %  values is less than the specified distance in a linear color space.  This
1293 %  method is used by MatteFloodFill() and other algorithms which compare
1294 %  two opacity values.
1295 %
1296 %  The format of the IsOpacitySimilar method is:
1297 %
1298 %      void IsOpacitySimilar(const Image *image,const PixelPacket *p,
1299 %        const PixelPacket *q)
1300 %
1301 %  A description of each parameter follows:
1302 %
1303 %    o image: the image.
1304 %
1305 %    o p: Pixel p.
1306 %
1307 %    o q: Pixel q.
1308 %
1309 */
1310 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
1311   const PixelPacket *p,const PixelPacket *q)
1312 {
1313   MagickRealType
1314     fuzz,
1315     pixel;
1316
1317   register MagickRealType
1318     distance;
1319
1320   if (image->matte == MagickFalse)
1321     return(MagickTrue);
1322   if (p->opacity == q->opacity)
1323     return(MagickTrue);
1324   fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
1325   pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
1326   distance=pixel*pixel;
1327   if (distance > fuzz)
1328     return(MagickFalse);
1329   return(MagickTrue);
1330 }
1331 \f
1332 /*
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 %                                                                             %
1335 %                                                                             %
1336 %                                                                             %
1337 %  L i s t C o l o r I n f o                                                  %
1338 %                                                                             %
1339 %                                                                             %
1340 %                                                                             %
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 %
1343 %  ListColorInfo() lists color names to the specified file.  Color names
1344 %  are a convenience.  Rather than defining a color by its red, green, and
1345 %  blue intensities just use a color name such as white, blue, or yellow.
1346 %
1347 %  The format of the ListColorInfo method is:
1348 %
1349 %      MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
1350 %
1351 %  A description of each parameter follows.
1352 %
1353 %    o file:  List color names to this file handle.
1354 %
1355 %    o exception: return any errors or warnings in this structure.
1356 %
1357 */
1358 MagickExport MagickBooleanType ListColorInfo(FILE *file,
1359   ExceptionInfo *exception)
1360 {
1361   char
1362     tuple[MaxTextExtent];
1363
1364   const char
1365     *path;
1366
1367   const ColorInfo
1368     **color_info;
1369
1370   register long
1371     i;
1372
1373   unsigned long
1374     number_colors;
1375
1376   /*
1377     List name and attributes of each color in the list.
1378   */
1379   if (file == (const FILE *) NULL)
1380     file=stdout;
1381   color_info=GetColorInfoList("*",&number_colors,exception);
1382   if (color_info == (const ColorInfo **) NULL)
1383     return(MagickFalse);
1384   path=(const char *) NULL;
1385   for (i=0; i < (long) number_colors; i++)
1386   {
1387     if (color_info[i]->stealth != MagickFalse)
1388       continue;
1389     if ((path == (const char *) NULL) ||
1390         (LocaleCompare(path,color_info[i]->path) != 0))
1391       {
1392         if (color_info[i]->path != (char *) NULL)
1393           (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
1394         (void) fprintf(file,"Name                  Color                  "
1395           "                       Compliance\n");
1396         (void) fprintf(file,"-------------------------------------------------"
1397           "------------------------------\n");
1398       }
1399     path=color_info[i]->path;
1400     (void) fprintf(file,"%-21.21s ",color_info[i]->name);
1401     GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
1402     (void) fprintf(file,"%-45.45s ",tuple);
1403     if ((color_info[i]->compliance & SVGCompliance) != 0)
1404       (void) fprintf(file,"SVG ");
1405     if ((color_info[i]->compliance & X11Compliance) != 0)
1406       (void) fprintf(file,"X11 ");
1407     if ((color_info[i]->compliance & XPMCompliance) != 0)
1408       (void) fprintf(file,"XPM ");
1409     (void) fprintf(file,"\n");
1410   }
1411   color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
1412   (void) fflush(file);
1413   return(MagickTrue);
1414 }
1415 \f
1416 /*
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418 %                                                                             %
1419 %                                                                             %
1420 %                                                                             %
1421 +   L o a d C o l o r L i s t                                                 %
1422 %                                                                             %
1423 %                                                                             %
1424 %                                                                             %
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 %
1427 %  LoadColorList() loads the color configuration file which provides a mapping
1428 %  between color attributes and a color name.
1429 %
1430 %  The format of the LoadColorList method is:
1431 %
1432 %      MagickBooleanType LoadColorList(const char *xml,const char *filename,
1433 %        const unsigned long depth,ExceptionInfo *exception)
1434 %
1435 %  A description of each parameter follows:
1436 %
1437 %    o xml:  The color list in XML format.
1438 %
1439 %    o filename:  The color list filename.
1440 %
1441 %    o depth: depth of <include /> statements.
1442 %
1443 %    o exception: return any errors or warnings in this structure.
1444 %
1445 */
1446 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
1447   const unsigned long depth,ExceptionInfo *exception)
1448 {
1449   char
1450     keyword[MaxTextExtent],
1451     *token;
1452
1453   ColorInfo
1454     *color_info;
1455
1456   const char
1457     *q;
1458
1459   MagickBooleanType
1460     status;
1461
1462   /*
1463     Load the color map file.
1464   */
1465   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1466     "Loading color file \"%s\" ...",filename);
1467   if (xml == (char *) NULL)
1468     return(MagickFalse);
1469   if (color_list == (LinkedListInfo *) NULL)
1470     {
1471       color_list=NewLinkedList(0);
1472       if (color_list == (LinkedListInfo *) NULL)
1473         {
1474           ThrowFileException(exception,ResourceLimitError,
1475             "MemoryAllocationFailed",filename);
1476           return(MagickFalse);
1477         }
1478     }
1479   status=MagickTrue;
1480   color_info=(ColorInfo *) NULL;
1481   token=AcquireString(xml);
1482   for (q=(char *) xml; *q != '\0'; )
1483   {
1484     /*
1485       Interpret XML.
1486     */
1487     GetMagickToken(q,&q,token);
1488     if (*token == '\0')
1489       break;
1490     (void) CopyMagickString(keyword,token,MaxTextExtent);
1491     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1492       {
1493         /*
1494           Doctype element.
1495         */
1496         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1497           GetMagickToken(q,&q,token);
1498         continue;
1499       }
1500     if (LocaleNCompare(keyword,"<!--",4) == 0)
1501       {
1502         /*
1503           Comment element.
1504         */
1505         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1506           GetMagickToken(q,&q,token);
1507         continue;
1508       }
1509     if (LocaleCompare(keyword,"<include") == 0)
1510       {
1511         /*
1512           Include element.
1513         */
1514         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1515         {
1516           (void) CopyMagickString(keyword,token,MaxTextExtent);
1517           GetMagickToken(q,&q,token);
1518           if (*token != '=')
1519             continue;
1520           GetMagickToken(q,&q,token);
1521           if (LocaleCompare(keyword,"file") == 0)
1522             {
1523               if (depth > 200)
1524                 (void) ThrowMagickException(exception,GetMagickModule(),
1525                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1526               else
1527                 {
1528                   char
1529                     path[MaxTextExtent],
1530                     *xml;
1531
1532                   GetPathComponent(filename,HeadPath,path);
1533                   if (*path != '\0')
1534                     (void) ConcatenateMagickString(path,DirectorySeparator,
1535                       MaxTextExtent);
1536                   if (*token == *DirectorySeparator)
1537                     (void) CopyMagickString(path,token,MaxTextExtent);
1538                   else
1539                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1540                   xml=FileToString(path,~0,exception);
1541                   if (xml != (char *) NULL)
1542                     {
1543                       status=LoadColorList(xml,path,depth+1,exception);
1544                       xml=(char *) RelinquishMagickMemory(xml);
1545                     }
1546                 }
1547             }
1548         }
1549         continue;
1550       }
1551     if (LocaleCompare(keyword,"<color") == 0)
1552       {
1553         /*
1554           Color element.
1555         */
1556         color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
1557         if (color_info == (ColorInfo *) NULL)
1558           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1559         (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
1560         color_info->path=ConstantString(filename);
1561         color_info->signature=MagickSignature;
1562         continue;
1563       }
1564     if (color_info == (ColorInfo *) NULL)
1565       continue;
1566     if (LocaleCompare(keyword,"/>") == 0)
1567       {
1568         status=AppendValueToLinkedList(color_list,color_info);
1569         if (status == MagickFalse)
1570           (void) ThrowMagickException(exception,GetMagickModule(),
1571             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1572             color_info->name);
1573         color_info=(ColorInfo *) NULL;
1574       }
1575     GetMagickToken(q,(const char **) NULL,token);
1576     if (*token != '=')
1577       continue;
1578     GetMagickToken(q,&q,token);
1579     GetMagickToken(q,&q,token);
1580     switch (*keyword)
1581     {
1582       case 'C':
1583       case 'c':
1584       {
1585         if (LocaleCompare((char *) keyword,"color") == 0)
1586           {
1587             (void) QueryMagickColor(token,&color_info->color,exception);
1588             break;
1589           }
1590         if (LocaleCompare((char *) keyword,"compliance") == 0)
1591           {
1592             long
1593               compliance;
1594
1595             compliance=color_info->compliance;
1596             if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
1597               compliance|=SVGCompliance;
1598             if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
1599               compliance|=X11Compliance;
1600             if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
1601               compliance|=XPMCompliance;
1602             color_info->compliance=(ComplianceType) compliance;
1603             break;
1604           }
1605         break;
1606       }
1607       case 'N':
1608       case 'n':
1609       {
1610         if (LocaleCompare((char *) keyword,"name") == 0)
1611           {
1612             color_info->name=ConstantString(token);
1613             break;
1614           }
1615         break;
1616       }
1617       case 'S':
1618       case 's':
1619       {
1620         if (LocaleCompare((char *) keyword,"stealth") == 0)
1621           {
1622             color_info->stealth=IsMagickTrue(token);
1623             break;
1624           }
1625         break;
1626       }
1627       default:
1628         break;
1629     }
1630   }
1631   token=(char *) RelinquishMagickMemory(token);
1632   return(status);
1633 }
1634 \f
1635 /*
1636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637 %                                                                             %
1638 %                                                                             %
1639 %                                                                             %
1640 %  L o a d C o l o r L i s t s                                                %
1641 %                                                                             %
1642 %                                                                             %
1643 %                                                                             %
1644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1645 %
1646 %  LoadColorList() loads one or more color configuration file which provides a
1647 %  mapping between color attributes and a color name.
1648 %
1649 %  The format of the LoadColorLists method is:
1650 %
1651 %      MagickBooleanType LoadColorLists(const char *filename,
1652 %        ExceptionInfo *exception)
1653 %
1654 %  A description of each parameter follows:
1655 %
1656 %    o filename: the font file name.
1657 %
1658 %    o exception: return any errors or warnings in this structure.
1659 %
1660 */
1661 static MagickBooleanType LoadColorLists(const char *filename,
1662   ExceptionInfo *exception)
1663 {
1664 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
1665   return(LoadColorList(ColorMap,"built-in",0,exception));
1666 #else
1667   const StringInfo
1668     *option;
1669
1670   LinkedListInfo
1671     *options;
1672
1673   MagickStatusType
1674     status;
1675
1676   status=MagickFalse;
1677   options=GetConfigureOptions(filename,exception);
1678   option=(const StringInfo *) GetNextValueInLinkedList(options);
1679   while (option != (const StringInfo *) NULL)
1680   {
1681     status|=LoadColorList((const char *) GetStringInfoDatum(option),
1682       GetStringInfoPath(option),0,exception);
1683     option=(const StringInfo *) GetNextValueInLinkedList(options);
1684   }
1685   options=DestroyConfigureOptions(options);
1686   if ((color_list == (LinkedListInfo *) NULL) ||
1687       (IsLinkedListEmpty(color_list) != MagickFalse))
1688     status|=LoadColorList(ColorMap,"built-in",0,exception);
1689   return(status != 0 ? MagickTrue : MagickFalse);
1690 #endif
1691 }
1692 \f
1693 /*
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695 %                                                                             %
1696 %                                                                             %
1697 %                                                                             %
1698 %   Q u e r y C o l o r D a t a b a s e                                       %
1699 %                                                                             %
1700 %                                                                             %
1701 %                                                                             %
1702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 %
1704 %  QueryColorDatabase() returns the red, green, blue, and opacity intensities
1705 %  for a given color name.
1706 %
1707 %  The format of the QueryColorDatabase method is:
1708 %
1709 %      MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
1710 %        ExceptionInfo *exception)
1711 %
1712 %  A description of each parameter follows:
1713 %
1714 %    o name: the color name (e.g. white, blue, yellow).
1715 %
1716 %    o color: the red, green, blue, and opacity intensities values of the
1717 %      named color in this structure.
1718 %
1719 %    o exception: return any errors or warnings in this structure.
1720 %
1721 */
1722
1723 static inline double MagickMin(const double x,const double y)
1724 {
1725   if (x < y)
1726     return(x);
1727   return(y);
1728 }
1729
1730 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
1731   PixelPacket *color,ExceptionInfo *exception)
1732 {
1733   MagickBooleanType
1734     status;
1735
1736   MagickPixelPacket
1737     pixel;
1738
1739   status=QueryMagickColor(name,&pixel,exception);
1740   color->opacity=RoundToQuantum(pixel.opacity);
1741   if (pixel.colorspace == CMYKColorspace)
1742     {
1743       color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
1744         QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
1745         pixel.index)+pixel.index))));
1746       color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
1747         QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
1748         pixel.index)+pixel.index))));
1749       color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
1750         QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
1751         pixel.index)+pixel.index))));
1752       return(status);
1753     }
1754   color->red=RoundToQuantum(pixel.red);
1755   color->green=RoundToQuantum(pixel.green);
1756   color->blue=RoundToQuantum(pixel.blue);
1757   return(status);
1758 }
1759 \f
1760 /*
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762 %                                                                             %
1763 %                                                                             %
1764 %                                                                             %
1765 %  Q u e r y C o l o r n a m e                                                %
1766 %                                                                             %
1767 %                                                                             %
1768 %                                                                             %
1769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770 %
1771 %  QueryColorname() returns a named color for the given color intensity.  If
1772 %  an exact match is not found, a rgb() color is returned instead.
1773 %
1774 %  The format of the QueryColorname method is:
1775 %
1776 %      MagickBooleanType QueryColorname(const Image *image,
1777 %        const PixelPacket *color,const ComplianceType compliance,char *name,
1778 %        ExceptionInfo *exception)
1779 %
1780 %  A description of each parameter follows.
1781 %
1782 %    o image: the image.
1783 %
1784 %    o color: the color intensities.
1785 %
1786 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
1787 %
1788 %    o name: Return the color name or hex value.
1789 %
1790 %    o exception: return any errors or warnings in this structure.
1791 %
1792 */
1793 MagickExport MagickBooleanType QueryColorname(const Image *image,
1794   const PixelPacket *color,const ComplianceType compliance,char *name,
1795   ExceptionInfo *exception)
1796 {
1797   MagickPixelPacket
1798     pixel;
1799
1800   GetMagickPixelPacket(image,&pixel);
1801   SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
1802   return(QueryMagickColorname(image,&pixel,compliance,name,exception));
1803 }
1804 \f
1805 /*
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 %                                                                             %
1808 %                                                                             %
1809 %                                                                             %
1810 %   Q u e r y M a g i c k C o l o r                                           %
1811 %                                                                             %
1812 %                                                                             %
1813 %                                                                             %
1814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815 %
1816 %  QueryMagickColor() returns the red, green, blue, and opacity intensities
1817 %  for a given color name.
1818 %
1819 %  The format of the QueryMagickColor method is:
1820 %
1821 %      MagickBooleanType QueryMagickColor(const char *name,
1822 %        MagickPixelPacket *color,ExceptionInfo *exception)
1823 %
1824 %  A description of each parameter follows:
1825 %
1826 %    o name: the color name (e.g. white, blue, yellow).
1827 %
1828 %    o color: the red, green, blue, and opacity intensities values of the
1829 %      named color in this structure.
1830 %
1831 %    o exception: return any errors or warnings in this structure.
1832 %
1833 */
1834 MagickExport MagickBooleanType QueryMagickColor(const char *name,
1835   MagickPixelPacket *color,ExceptionInfo *exception)
1836 {
1837   GeometryInfo
1838     geometry_info;
1839
1840   long
1841     type;
1842
1843   MagickRealType
1844     scale;
1845
1846   MagickStatusType
1847     flags;
1848
1849   register const ColorInfo
1850     *p;
1851
1852   register long
1853     i;
1854
1855   /*
1856     Initialize color return value.
1857   */
1858   assert(name != (const char *) NULL);
1859   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
1860   assert(color != (MagickPixelPacket *) NULL);
1861   GetMagickPixelPacket((Image *) NULL,color);
1862   if ((name == (char *) NULL) || (*name == '\0'))
1863     name=BackgroundColor;
1864   while (isspace((int) ((unsigned char) *name)) != 0)
1865     name++;
1866   if (*name == '#')
1867     {
1868       char
1869         c;
1870
1871       LongPixelPacket
1872         pixel;
1873
1874       QuantumAny
1875         range;
1876
1877       unsigned long
1878         depth,
1879         n;
1880
1881       /*
1882         Parse hex color.
1883       */
1884       (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1885       name++;
1886       for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
1887       if ((n % 3) == 0)
1888         {
1889           do
1890           {
1891             pixel.red=pixel.green;
1892             pixel.green=pixel.blue;
1893             pixel.blue=0;
1894             for (i=(long) (n/3-1); i >= 0; i--)
1895             {
1896               c=(*name++);
1897               pixel.blue<<=4;
1898               if ((c >= '0') && (c <= '9'))
1899                 pixel.blue|=(int) (c-'0');
1900               else
1901                 if ((c >= 'A') && (c <= 'F'))
1902                   pixel.blue|=(int) c-((int) 'A'-10);
1903                 else
1904                   if ((c >= 'a') && (c <= 'f'))
1905                     pixel.blue|=(int) c-((int) 'a'-10);
1906                   else
1907                     return(MagickFalse);
1908             }
1909           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
1910           depth=4*(n/3);
1911         }
1912       else
1913         {
1914           if ((n % 4) != 0)
1915             {
1916               (void) ThrowMagickException(exception,GetMagickModule(),
1917                 OptionWarning,"UnrecognizedColor","`%s'",name);
1918               return(MagickFalse);
1919             }
1920           do
1921           {
1922             pixel.red=pixel.green;
1923             pixel.green=pixel.blue;
1924             pixel.blue=pixel.opacity;
1925             pixel.opacity=0;
1926             for (i=(long) (n/4-1); i >= 0; i--)
1927             {
1928               c=(*name++);
1929               pixel.opacity<<=4;
1930               if ((c >= '0') && (c <= '9'))
1931                 pixel.opacity|=(int) (c-'0');
1932               else
1933                 if ((c >= 'A') && (c <= 'F'))
1934                   pixel.opacity|=(int) c-((int) 'A'-10);
1935                 else
1936                   if ((c >= 'a') && (c <= 'f'))
1937                     pixel.opacity|=(int) c-((int) 'a'-10);
1938                   else
1939                     return(MagickFalse);
1940             }
1941           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
1942           depth=4*(n/4);
1943         }
1944       color->colorspace=RGBColorspace;
1945       color->matte=MagickFalse;
1946       range=GetQuantumRange(depth);
1947       color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
1948       color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
1949       color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
1950       color->opacity=(MagickRealType) OpaqueOpacity;
1951       if ((n % 3) != 0)
1952         {
1953           color->matte=MagickTrue;
1954           color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
1955             pixel.opacity,range));
1956         }
1957       color->index=0.0;
1958       return(MagickTrue);
1959     }
1960   if (strchr(name,'(') != (char *) NULL)
1961     {
1962       char
1963         colorspace[MaxTextExtent];
1964
1965       /*
1966         Parse color of the form rgb(100,255,0).
1967       */
1968       (void) CopyMagickString(colorspace,name,MaxTextExtent);
1969       for (i=0; colorspace[i] != '\0'; i++)
1970         if (colorspace[i] == '(')
1971           break;
1972       colorspace[i--]='\0';
1973       LocaleLower(colorspace);
1974       color->matte=MagickFalse;
1975       if ((i > 0) && (colorspace[i] == 'a'))
1976         {
1977           colorspace[i]='\0';
1978           color->matte=MagickTrue;
1979         }
1980       type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
1981       if (type < 0)
1982         {
1983           (void) ThrowMagickException(exception,GetMagickModule(),
1984             OptionWarning,"UnrecognizedColor","`%s'",name);
1985           return(MagickFalse);
1986         }
1987       color->colorspace=(ColorspaceType) type;
1988       SetGeometryInfo(&geometry_info);
1989       flags=ParseGeometry(name+i+1,&geometry_info);
1990       scale=(MagickRealType) ScaleCharToQuantum(1);
1991       if ((flags & PercentValue) != 0)
1992         scale=(MagickRealType) (QuantumRange/100.0);
1993       if ((flags & RhoValue) != 0)
1994         color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
1995       if ((flags & SigmaValue) != 0)
1996         color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
1997       if ((flags & XiValue) != 0)
1998         color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
1999       color->opacity=(MagickRealType) OpaqueOpacity;
2000       if ((flags & PsiValue) != 0)
2001         {
2002           if (color->colorspace == CMYKColorspace)
2003             color->index=(MagickRealType) RoundToQuantum(scale*
2004               geometry_info.psi);
2005           else
2006             if (color->matte != MagickFalse)
2007               color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2008                 (QuantumRange-QuantumRange*geometry_info.psi));
2009         }
2010       if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
2011         color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2012           (QuantumRange-QuantumRange*geometry_info.chi));
2013       if (LocaleCompare(colorspace,"gray") == 0)
2014         {
2015           color->green=color->red;
2016           color->blue=color->red;
2017           if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
2018             color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2019               (QuantumRange-QuantumRange*geometry_info.sigma));
2020         }
2021       if ((LocaleCompare(colorspace,"HSB") == 0) ||
2022           (LocaleCompare(colorspace,"HSL") == 0) ||
2023           (LocaleCompare(colorspace,"HWB") == 0))
2024         {
2025           PixelPacket
2026             pixel;
2027
2028           scale=1.0/360.0;
2029           if ((flags & PercentValue) != 0)
2030             scale=1.0/100.0;
2031           geometry_info.rho*=360.0*scale;
2032           scale=1.0/255.0;
2033           if ((flags & PercentValue) != 0)
2034             scale=1.0/100.0;
2035           geometry_info.sigma*=scale;
2036           geometry_info.xi*=scale;
2037           if (LocaleCompare(colorspace,"HSB") == 0)
2038             ConvertHSBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2039               360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2040               &pixel.green,&pixel.blue);
2041           else
2042             if (LocaleCompare(colorspace,"HSL") == 0)
2043               ConvertHSLToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2044                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2045                 &pixel.green,&pixel.blue);
2046             else
2047               ConvertHWBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2048                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2049                 &pixel.green,&pixel.blue);
2050           color->colorspace=RGBColorspace;
2051           color->red=(MagickRealType) pixel.red;
2052           color->green=(MagickRealType) pixel.green;
2053           color->blue=(MagickRealType) pixel.blue;
2054         }
2055       return(MagickTrue);
2056     }
2057   /*
2058     Parse named color.
2059   */
2060   p=GetColorInfo(name,exception);
2061   if (p == (const ColorInfo *) NULL)
2062     return(MagickFalse);
2063   color->colorspace=RGBColorspace;
2064   color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
2065   color->red=(MagickRealType) p->color.red;
2066   color->green=(MagickRealType) p->color.green;
2067   color->blue=(MagickRealType) p->color.blue;
2068   color->opacity=(MagickRealType) p->color.opacity;
2069   color->index=0.0;
2070   return(MagickTrue);
2071 }
2072 \f
2073 /*
2074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2075 %                                                                             %
2076 %                                                                             %
2077 %                                                                             %
2078 %  Q u e r y M a g i c k C o l o r n a m e                                    %
2079 %                                                                             %
2080 %                                                                             %
2081 %                                                                             %
2082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2083 %
2084 %  QueryMagickColorname() returns a named color for the given color intensity.
2085 %  If an exact match is not found, a hex value is returned instead.  For
2086 %  example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
2087 %  returns #dfdfdf.
2088 %
2089 %  The format of the QueryMagickColorname method is:
2090 %
2091 %      MagickBooleanType QueryMagickColorname(const Image *image,
2092 %        const PixelPacket *color,const ComplianceType compliance,char *name,
2093 %        ExceptionInfo *exception)
2094 %
2095 %  A description of each parameter follows.
2096 %
2097 %    o image: the image.
2098 %
2099 %    o color: the color intensities.
2100 %
2101 %    o Compliance: Adhere to this color standard: SVG, X11, or XPM.
2102 %
2103 %    o name: Return the color name or hex value.
2104 %
2105 %    o exception: return any errors or warnings in this structure.
2106 %
2107 */
2108 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
2109   const MagickPixelPacket *color,const ComplianceType compliance,
2110   char *name,ExceptionInfo *exception)
2111 {
2112   MagickPixelPacket
2113     pixel;
2114
2115   MagickRealType
2116     opacity;
2117
2118   register const ColorInfo
2119     *p;
2120
2121   *name='\0';
2122   pixel=(*color);
2123   if (compliance == XPMCompliance)
2124     {
2125       pixel.matte=MagickFalse;
2126       pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
2127       GetColorTuple(&pixel,MagickTrue,name);
2128       return(MagickTrue);
2129     }
2130   GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
2131     name);
2132   (void) GetColorInfo("*",exception);
2133   ResetLinkedListIterator(color_list);
2134   opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
2135   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
2136   while (p != (const ColorInfo *) NULL)
2137   {
2138     if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
2139          (p->color.green == color->green) && (p->color.blue == color->blue) &&
2140          (p->color.opacity == opacity))
2141       {
2142         (void) CopyMagickString(name,p->name,MaxTextExtent);
2143         break;
2144       }
2145     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
2146   }
2147   return(MagickTrue);
2148 }