]> 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 G r a y I m a g e                                                   %
1072 %                                                                             %
1073 %                                                                             %
1074 %                                                                             %
1075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 %
1077 %  IsGrayImage() returns MagickTrue if all the pixels in the image have the
1078 %  same red, green, and blue intensities.
1079 %
1080 %  The format of the IsGrayImage method is:
1081 %
1082 %      MagickBooleanType IsGrayImage(const Image *image,
1083 %        ExceptionInfo *exception)
1084 %
1085 %  A description of each parameter follows:
1086 %
1087 %    o image: the image.
1088 %
1089 %    o exception: return any errors or warnings in this structure.
1090 %
1091 */
1092 MagickExport MagickBooleanType IsGrayImage(const Image *image,
1093   ExceptionInfo *exception)
1094 {
1095   ImageType
1096     type;
1097
1098   register const PixelPacket
1099     *p;
1100
1101   assert(image != (Image *) NULL);
1102   assert(image->signature == MagickSignature);
1103   if (image->debug != MagickFalse)
1104     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1105   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1106       (image->type == GrayscaleMatteType))
1107     return(MagickTrue);
1108   if (image->colorspace == CMYKColorspace)
1109     return(MagickFalse);
1110   type=BilevelType;
1111   switch (image->storage_class)
1112   {
1113     case DirectClass:
1114     case UndefinedClass:
1115     {
1116       long
1117         y;
1118
1119       register long
1120         x;
1121
1122       CacheView
1123         *image_view;
1124
1125       image_view=AcquireCacheView(image);
1126       for (y=0; y < (long) image->rows; y++)
1127       {
1128         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1129         if (p == (const PixelPacket *) NULL)
1130           break;
1131         for (x=0; x < (long) image->columns; x++)
1132         {
1133           if (IsGrayPixel(p) == MagickFalse)
1134             {
1135               type=UndefinedType;
1136               break;
1137             }
1138           if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1139             type=GrayscaleType;
1140           p++;
1141         }
1142         if (type == UndefinedType)
1143           break;
1144       }
1145       image_view=DestroyCacheView(image_view);
1146       break;
1147     }
1148     case PseudoClass:
1149     {
1150       register long
1151         i;
1152
1153       p=image->colormap;
1154       for (i=0; i < (long) image->colors; i++)
1155       {
1156         if (IsGrayPixel(p) == MagickFalse)
1157           {
1158             type=UndefinedType;
1159             break;
1160           }
1161         if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1162           type=GrayscaleType;
1163         p++;
1164       }
1165       break;
1166     }
1167   }
1168   if (type == UndefinedType)
1169     return(MagickFalse);
1170   ((Image *) image)->type=type;
1171   if ((type == GrayscaleType) && (image->matte != MagickFalse))
1172     ((Image *) image)->type=GrayscaleMatteType;
1173   return(MagickTrue);
1174 }
1175 \f
1176 /*
1177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178 %                                                                             %
1179 %                                                                             %
1180 %                                                                             %
1181 +   I s I m a g e S i m i l a r                                               %
1182 %                                                                             %
1183 %                                                                             %
1184 %                                                                             %
1185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 %
1187 %  IsImageSimilar() returns true if the target is similar to a region of the
1188 %  image.
1189 %
1190 %  The format of the IsImageSimilar method is:
1191 %
1192 %      MagickBooleanType IsImageSimilar(const Image *image,
1193 %        const Image *target_image,long *x_offset,long *y_offset,
1194 %        ExceptionInfo *exception)
1195 %
1196 %  A description of each parameter follows:
1197 %
1198 %    o image: the image.
1199 %
1200 %    o target_image: the target image.
1201 %
1202 %    o x_offset: On input the starting x position to search for a match;
1203 %      on output the x position of the first match found.
1204 %
1205 %    o y_offset: On input the starting y position to search for a match;
1206 %      on output the y position of the first match found.
1207 %
1208 %    o exception: return any errors or warnings in this structure.
1209 %
1210 */
1211 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
1212   const Image *target_image,long *x_offset,long *y_offset,
1213   ExceptionInfo *exception)
1214 {
1215 #define SearchImageText  "  Searching image...  "
1216
1217   long
1218     j,
1219     y;
1220
1221   MagickBooleanType
1222     status;
1223
1224   MagickPixelPacket
1225     target,
1226     pixel;
1227
1228   register const PixelPacket
1229     *p,
1230     *q;
1231
1232   register const IndexPacket
1233     *indexes,
1234     *target_indexes;
1235
1236   register long
1237     i,
1238     x;
1239
1240   CacheView
1241     *image_view,
1242     *target_view;
1243
1244   assert(image != (Image *) NULL);
1245   assert(image->signature == MagickSignature);
1246   if (image->debug != MagickFalse)
1247     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1248   assert(target_image != (Image *) NULL);
1249   assert(target_image->signature == MagickSignature);
1250   assert(x_offset != (long *) NULL);
1251   assert(y_offset != (long *) NULL);
1252   assert(exception != (ExceptionInfo *) NULL);
1253   x=0;
1254   GetMagickPixelPacket(image,&pixel);
1255   GetMagickPixelPacket(image,&target);
1256   image_view=AcquireCacheView(image);
1257   target_view=AcquireCacheView(target_image);
1258   for (y=(*y_offset); y < (long) image->rows; y++)
1259   {
1260     for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
1261     {
1262       for (j=0; j < (long) target_image->rows; j++)
1263       {
1264         for (i=0; i < (long) target_image->columns; i++)
1265         {
1266           p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
1267           indexes=GetCacheViewVirtualIndexQueue(image_view);
1268           SetMagickPixelPacket(image,p,indexes,&pixel);
1269           q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
1270           target_indexes=GetCacheViewVirtualIndexQueue(target_view);
1271           SetMagickPixelPacket(image,q,target_indexes,&target);
1272           if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
1273             break;
1274         }
1275         if (i < (long) target_image->columns)
1276           break;
1277       }
1278       if (j == (long) target_image->rows)
1279         break;
1280     }
1281     if (x < (long) image->columns)
1282       break;
1283     if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1284         (QuantumTick(y,image->rows) != MagickFalse))
1285       {
1286         status=image->progress_monitor(SearchImageText,y,image->rows,
1287           image->client_data);
1288         if (status == MagickFalse)
1289           break;
1290       }
1291   }
1292   target_view=DestroyCacheView(target_view);
1293   image_view=DestroyCacheView(image_view);
1294   *x_offset=x;
1295   *y_offset=y;
1296   return(y < (long) image->rows ? MagickTrue : MagickFalse);
1297 }
1298 \f
1299 /*
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 %                                                                             %
1302 %                                                                             %
1303 %                                                                             %
1304 +   I s M a g i c k C o l o r S i m i l a r                                   %
1305 %                                                                             %
1306 %                                                                             %
1307 %                                                                             %
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 %
1310 %  IsMagickColorSimilar() returns true if the distance between two colors is
1311 %  less than the specified distance in a linear three dimensional color space.
1312 %  This method is used by ColorFloodFill() and other algorithms which
1313 %  compare two colors.
1314 %
1315 %  The format of the IsMagickColorSimilar method is:
1316 %
1317 %      MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
1318 %        const MagickPixelPacket *q)
1319 %
1320 %  A description of each parameter follows:
1321 %
1322 %    o p: Pixel p.
1323 %
1324 %    o q: Pixel q.
1325 %
1326 */
1327 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
1328   const MagickPixelPacket *q)
1329 {
1330   MagickRealType
1331     fuzz,
1332     pixel;
1333
1334   register MagickRealType
1335     alpha,
1336     beta,
1337     distance;
1338
1339   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
1340     return(IsMagickColorEqual(p,q));
1341   if (p->fuzz == 0.0)
1342     fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
1343   else
1344     if (q->fuzz == 0.0)
1345       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
1346     else
1347       fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
1348   alpha=1.0;
1349   if (p->matte != MagickFalse)
1350     alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1351   beta=1.0;
1352   if (q->matte != MagickFalse)
1353     beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1354   if (p->colorspace == CMYKColorspace)
1355     {
1356       alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
1357       beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
1358     }
1359   pixel=alpha*p->red-beta*q->red;
1360   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
1361       (p->colorspace == HWBColorspace))
1362     {
1363       if (fabs(p->red-q->red) > (QuantumRange/2))
1364         {
1365           if (p->red > (QuantumRange/2))
1366             pixel=alpha*(p->red-QuantumRange)-beta*q->red;
1367           else
1368             pixel=alpha*p->red-beta*(q->red-QuantumRange);
1369         }
1370         pixel*=2;
1371      }
1372   distance=pixel*pixel;
1373   if (distance > fuzz)
1374     return(MagickFalse);
1375   pixel=alpha*p->green-beta*q->green;
1376   distance+=pixel*pixel;
1377   if (distance > fuzz)
1378     return(MagickFalse);
1379   pixel=alpha*p->blue-beta*q->blue;
1380   distance+=pixel*pixel;
1381   if (distance > fuzz)
1382     return(MagickFalse);
1383   pixel=p->opacity-q->opacity;
1384   distance+=pixel*pixel;
1385   if (distance > fuzz)
1386     return(MagickFalse);
1387   return(MagickTrue);
1388 }
1389 \f
1390 /*
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 %                                                                             %
1393 %                                                                             %
1394 %                                                                             %
1395 %   I s M o n o c h r o m e I m a g e                                         %
1396 %                                                                             %
1397 %                                                                             %
1398 %                                                                             %
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 %
1401 %  IsMonochromeImage() returns MagickTrue if all the pixels in the image have
1402 %  the same red, green, and blue intensities and the intensity is either
1403 %  0 or QuantumRange.
1404 %
1405 %  The format of the IsMonochromeImage method is:
1406 %
1407 %      MagickBooleanType IsMonochromeImage(const Image *image,
1408 %        ExceptionInfo *exception)
1409 %
1410 %  A description of each parameter follows:
1411 %
1412 %    o image: the image.
1413 %
1414 %    o exception: return any errors or warnings in this structure.
1415 %
1416 */
1417 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
1418   ExceptionInfo *exception)
1419 {
1420   ImageType
1421     type;
1422
1423   register const PixelPacket
1424     *p;
1425
1426   assert(image != (Image *) NULL);
1427   assert(image->signature == MagickSignature);
1428   if (image->debug != MagickFalse)
1429     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1430   if (image->type == BilevelType)
1431     return(MagickTrue);
1432   if (image->colorspace == CMYKColorspace)
1433     return(MagickFalse);
1434   type=BilevelType;
1435   switch (image->storage_class)
1436   {
1437     case DirectClass:
1438     case UndefinedClass:
1439     {
1440       long
1441         y;
1442
1443       register long
1444         x;
1445
1446       CacheView
1447         *image_view;
1448
1449       image_view=AcquireCacheView(image);
1450       for (y=0; y < (long) image->rows; y++)
1451       {
1452         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1453         if (p == (const PixelPacket *) NULL)
1454           break;
1455         for (x=0; x < (long) image->columns; x++)
1456         {
1457           if (IsMonochromePixel(p) == MagickFalse)
1458             {
1459               type=UndefinedType;
1460               break;
1461             }
1462           p++;
1463         }
1464         if (type == UndefinedType)
1465           break;
1466       }
1467       image_view=DestroyCacheView(image_view);
1468       if (y == (long) image->rows)
1469         ((Image *) image)->type=BilevelType;
1470       break;
1471     }
1472     case PseudoClass:
1473     {
1474       register long
1475         i;
1476
1477       p=image->colormap;
1478       for (i=0; i < (long) image->colors; i++)
1479       {
1480         if (IsMonochromePixel(p) == MagickFalse)
1481           {
1482             type=UndefinedType;
1483             break;
1484           }
1485         p++;
1486       }
1487       break;
1488     }
1489   }
1490   if (type == UndefinedType)
1491     return(MagickFalse);
1492   ((Image *) image)->type=type;
1493   return(MagickTrue);
1494 }
1495 \f
1496 /*
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1498 %                                                                             %
1499 %                                                                             %
1500 %                                                                             %
1501 +   I s O p a c i t y S i m i l a r                                           %
1502 %                                                                             %
1503 %                                                                             %
1504 %                                                                             %
1505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 %
1507 %  IsOpacitySimilar() returns true if the distance between two opacity
1508 %  values is less than the specified distance in a linear color space.  This
1509 %  method is used by MatteFloodFill() and other algorithms which compare
1510 %  two opacity values.
1511 %
1512 %  The format of the IsOpacitySimilar method is:
1513 %
1514 %      void IsOpacitySimilar(const Image *image,const PixelPacket *p,
1515 %        const PixelPacket *q)
1516 %
1517 %  A description of each parameter follows:
1518 %
1519 %    o image: the image.
1520 %
1521 %    o p: Pixel p.
1522 %
1523 %    o q: Pixel q.
1524 %
1525 */
1526 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
1527   const PixelPacket *p,const PixelPacket *q)
1528 {
1529   MagickRealType
1530     fuzz,
1531     pixel;
1532
1533   register MagickRealType
1534     distance;
1535
1536   if (image->matte == MagickFalse)
1537     return(MagickTrue);
1538   if (p->opacity == q->opacity)
1539     return(MagickTrue);
1540   fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
1541   pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
1542   distance=pixel*pixel;
1543   if (distance > fuzz)
1544     return(MagickFalse);
1545   return(MagickTrue);
1546 }
1547 \f
1548 /*
1549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 %                                                                             %
1551 %                                                                             %
1552 %                                                                             %
1553 %     I s O p a q u e I m a g e                                               %
1554 %                                                                             %
1555 %                                                                             %
1556 %                                                                             %
1557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 %
1559 %  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
1560 %  an opacity value other than opaque (0).
1561 %
1562 %  The format of the IsOpaqueImage method is:
1563 %
1564 %      MagickBooleanType IsOpaqueImage(const Image *image,
1565 %        ExceptionInfo *exception)
1566 %
1567 %  A description of each parameter follows:
1568 %
1569 %    o image: the image.
1570 %
1571 %    o exception: return any errors or warnings in this structure.
1572 %
1573 */
1574 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
1575   ExceptionInfo *exception)
1576 {
1577   long
1578     y;
1579
1580   register const PixelPacket
1581     *p;
1582
1583   register long
1584     x;
1585
1586   CacheView
1587     *image_view;
1588
1589   /*
1590     Determine if image is opaque.
1591   */
1592   assert(image != (Image *) NULL);
1593   assert(image->signature == MagickSignature);
1594   if (image->debug != MagickFalse)
1595     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1596   if (image->matte == MagickFalse)
1597     return(MagickTrue);
1598   image_view=AcquireCacheView(image);
1599   for (y=0; y < (long) image->rows; y++)
1600   {
1601     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1602     if (p == (const PixelPacket *) NULL)
1603       break;
1604     for (x=0; x < (long) image->columns; x++)
1605     {
1606       if (p->opacity != OpaqueOpacity)
1607         break;
1608       p++;
1609     }
1610     if (x < (long) image->columns)
1611      break;
1612   }
1613   image_view=DestroyCacheView(image_view);
1614   return(y < (long) image->rows ? MagickFalse : MagickTrue);
1615 }
1616 \f
1617 /*
1618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 %                                                                             %
1620 %                                                                             %
1621 %                                                                             %
1622 %  L i s t C o l o r I n f o                                                  %
1623 %                                                                             %
1624 %                                                                             %
1625 %                                                                             %
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 %
1628 %  ListColorInfo() lists color names to the specified file.  Color names
1629 %  are a convenience.  Rather than defining a color by its red, green, and
1630 %  blue intensities just use a color name such as white, blue, or yellow.
1631 %
1632 %  The format of the ListColorInfo method is:
1633 %
1634 %      MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
1635 %
1636 %  A description of each parameter follows.
1637 %
1638 %    o file:  List color names to this file handle.
1639 %
1640 %    o exception: return any errors or warnings in this structure.
1641 %
1642 */
1643 MagickExport MagickBooleanType ListColorInfo(FILE *file,
1644   ExceptionInfo *exception)
1645 {
1646   char
1647     tuple[MaxTextExtent];
1648
1649   const char
1650     *path;
1651
1652   const ColorInfo
1653     **color_info;
1654
1655   register long
1656     i;
1657
1658   unsigned long
1659     number_colors;
1660
1661   /*
1662     List name and attributes of each color in the list.
1663   */
1664   if (file == (const FILE *) NULL)
1665     file=stdout;
1666   color_info=GetColorInfoList("*",&number_colors,exception);
1667   if (color_info == (const ColorInfo **) NULL)
1668     return(MagickFalse);
1669   path=(const char *) NULL;
1670   for (i=0; i < (long) number_colors; i++)
1671   {
1672     if (color_info[i]->stealth != MagickFalse)
1673       continue;
1674     if ((path == (const char *) NULL) ||
1675         (LocaleCompare(path,color_info[i]->path) != 0))
1676       {
1677         if (color_info[i]->path != (char *) NULL)
1678           (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
1679         (void) fprintf(file,"Name                  Color                  "
1680           "                       Compliance\n");
1681         (void) fprintf(file,"-------------------------------------------------"
1682           "------------------------------\n");
1683       }
1684     path=color_info[i]->path;
1685     (void) fprintf(file,"%-21.21s ",color_info[i]->name);
1686     GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
1687     (void) fprintf(file,"%-45.45s ",tuple);
1688     if ((color_info[i]->compliance & SVGCompliance) != 0)
1689       (void) fprintf(file,"SVG ");
1690     if ((color_info[i]->compliance & X11Compliance) != 0)
1691       (void) fprintf(file,"X11 ");
1692     if ((color_info[i]->compliance & XPMCompliance) != 0)
1693       (void) fprintf(file,"XPM ");
1694     (void) fprintf(file,"\n");
1695   }
1696   color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
1697   (void) fflush(file);
1698   return(MagickTrue);
1699 }
1700 \f
1701 /*
1702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 %                                                                             %
1704 %                                                                             %
1705 %                                                                             %
1706 +   L o a d C o l o r L i s t                                                 %
1707 %                                                                             %
1708 %                                                                             %
1709 %                                                                             %
1710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711 %
1712 %  LoadColorList() loads the color configuration file which provides a mapping
1713 %  between color attributes and a color name.
1714 %
1715 %  The format of the LoadColorList method is:
1716 %
1717 %      MagickBooleanType LoadColorList(const char *xml,const char *filename,
1718 %        const unsigned long depth,ExceptionInfo *exception)
1719 %
1720 %  A description of each parameter follows:
1721 %
1722 %    o xml:  The color list in XML format.
1723 %
1724 %    o filename:  The color list filename.
1725 %
1726 %    o depth: depth of <include /> statements.
1727 %
1728 %    o exception: return any errors or warnings in this structure.
1729 %
1730 */
1731 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
1732   const unsigned long depth,ExceptionInfo *exception)
1733 {
1734   char
1735     keyword[MaxTextExtent],
1736     *token;
1737
1738   ColorInfo
1739     *color_info;
1740
1741   const char
1742     *q;
1743
1744   MagickBooleanType
1745     status;
1746
1747   /*
1748     Load the color map file.
1749   */
1750   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1751     "Loading color file \"%s\" ...",filename);
1752   if (xml == (char *) NULL)
1753     return(MagickFalse);
1754   if (color_list == (LinkedListInfo *) NULL)
1755     {
1756       color_list=NewLinkedList(0);
1757       if (color_list == (LinkedListInfo *) NULL)
1758         {
1759           ThrowFileException(exception,ResourceLimitError,
1760             "MemoryAllocationFailed",filename);
1761           return(MagickFalse);
1762         }
1763     }
1764   status=MagickTrue;
1765   color_info=(ColorInfo *) NULL;
1766   token=AcquireString(xml);
1767   for (q=(char *) xml; *q != '\0'; )
1768   {
1769     /*
1770       Interpret XML.
1771     */
1772     GetMagickToken(q,&q,token);
1773     if (*token == '\0')
1774       break;
1775     (void) CopyMagickString(keyword,token,MaxTextExtent);
1776     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1777       {
1778         /*
1779           Doctype element.
1780         */
1781         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1782           GetMagickToken(q,&q,token);
1783         continue;
1784       }
1785     if (LocaleNCompare(keyword,"<!--",4) == 0)
1786       {
1787         /*
1788           Comment element.
1789         */
1790         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1791           GetMagickToken(q,&q,token);
1792         continue;
1793       }
1794     if (LocaleCompare(keyword,"<include") == 0)
1795       {
1796         /*
1797           Include element.
1798         */
1799         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1800         {
1801           (void) CopyMagickString(keyword,token,MaxTextExtent);
1802           GetMagickToken(q,&q,token);
1803           if (*token != '=')
1804             continue;
1805           GetMagickToken(q,&q,token);
1806           if (LocaleCompare(keyword,"file") == 0)
1807             {
1808               if (depth > 200)
1809                 (void) ThrowMagickException(exception,GetMagickModule(),
1810                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1811               else
1812                 {
1813                   char
1814                     path[MaxTextExtent],
1815                     *xml;
1816
1817                   GetPathComponent(filename,HeadPath,path);
1818                   if (*path != '\0')
1819                     (void) ConcatenateMagickString(path,DirectorySeparator,
1820                       MaxTextExtent);
1821                   if (*token == *DirectorySeparator)
1822                     (void) CopyMagickString(path,token,MaxTextExtent);
1823                   else
1824                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1825                   xml=FileToString(path,~0,exception);
1826                   if (xml != (char *) NULL)
1827                     {
1828                       status=LoadColorList(xml,path,depth+1,exception);
1829                       xml=(char *) RelinquishMagickMemory(xml);
1830                     }
1831                 }
1832             }
1833         }
1834         continue;
1835       }
1836     if (LocaleCompare(keyword,"<color") == 0)
1837       {
1838         /*
1839           Color element.
1840         */
1841         color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
1842         if (color_info == (ColorInfo *) NULL)
1843           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1844         (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
1845         color_info->path=ConstantString(filename);
1846         color_info->signature=MagickSignature;
1847         continue;
1848       }
1849     if (color_info == (ColorInfo *) NULL)
1850       continue;
1851     if (LocaleCompare(keyword,"/>") == 0)
1852       {
1853         status=AppendValueToLinkedList(color_list,color_info);
1854         if (status == MagickFalse)
1855           (void) ThrowMagickException(exception,GetMagickModule(),
1856             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1857             color_info->name);
1858         color_info=(ColorInfo *) NULL;
1859       }
1860     GetMagickToken(q,(const char **) NULL,token);
1861     if (*token != '=')
1862       continue;
1863     GetMagickToken(q,&q,token);
1864     GetMagickToken(q,&q,token);
1865     switch (*keyword)
1866     {
1867       case 'C':
1868       case 'c':
1869       {
1870         if (LocaleCompare((char *) keyword,"color") == 0)
1871           {
1872             (void) QueryMagickColor(token,&color_info->color,exception);
1873             break;
1874           }
1875         if (LocaleCompare((char *) keyword,"compliance") == 0)
1876           {
1877             long
1878               compliance;
1879
1880             compliance=color_info->compliance;
1881             if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
1882               compliance|=SVGCompliance;
1883             if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
1884               compliance|=X11Compliance;
1885             if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
1886               compliance|=XPMCompliance;
1887             color_info->compliance=(ComplianceType) compliance;
1888             break;
1889           }
1890         break;
1891       }
1892       case 'N':
1893       case 'n':
1894       {
1895         if (LocaleCompare((char *) keyword,"name") == 0)
1896           {
1897             color_info->name=ConstantString(token);
1898             break;
1899           }
1900         break;
1901       }
1902       case 'S':
1903       case 's':
1904       {
1905         if (LocaleCompare((char *) keyword,"stealth") == 0)
1906           {
1907             color_info->stealth=IsMagickTrue(token);
1908             break;
1909           }
1910         break;
1911       }
1912       default:
1913         break;
1914     }
1915   }
1916   token=(char *) RelinquishMagickMemory(token);
1917   return(status);
1918 }
1919 \f
1920 /*
1921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922 %                                                                             %
1923 %                                                                             %
1924 %                                                                             %
1925 %  L o a d C o l o r L i s t s                                                %
1926 %                                                                             %
1927 %                                                                             %
1928 %                                                                             %
1929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930 %
1931 %  LoadColorList() loads one or more color configuration file which provides a
1932 %  mapping between color attributes and a color name.
1933 %
1934 %  The format of the LoadColorLists method is:
1935 %
1936 %      MagickBooleanType LoadColorLists(const char *filename,
1937 %        ExceptionInfo *exception)
1938 %
1939 %  A description of each parameter follows:
1940 %
1941 %    o filename: the font file name.
1942 %
1943 %    o exception: return any errors or warnings in this structure.
1944 %
1945 */
1946 static MagickBooleanType LoadColorLists(const char *filename,
1947   ExceptionInfo *exception)
1948 {
1949 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
1950   return(LoadColorList(ColorMap,"built-in",0,exception));
1951 #else
1952   const StringInfo
1953     *option;
1954
1955   LinkedListInfo
1956     *options;
1957
1958   MagickStatusType
1959     status;
1960
1961   status=MagickFalse;
1962   options=GetConfigureOptions(filename,exception);
1963   option=(const StringInfo *) GetNextValueInLinkedList(options);
1964   while (option != (const StringInfo *) NULL)
1965   {
1966     status|=LoadColorList((const char *) GetStringInfoDatum(option),
1967       GetStringInfoPath(option),0,exception);
1968     option=(const StringInfo *) GetNextValueInLinkedList(options);
1969   }
1970   options=DestroyConfigureOptions(options);
1971   if ((color_list == (LinkedListInfo *) NULL) ||
1972       (IsLinkedListEmpty(color_list) != MagickFalse))
1973     status|=LoadColorList(ColorMap,"built-in",0,exception);
1974   return(status != 0 ? MagickTrue : MagickFalse);
1975 #endif
1976 }
1977 \f
1978 /*
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 %                                                                             %
1981 %                                                                             %
1982 %                                                                             %
1983 %   Q u e r y C o l o r D a t a b a s e                                       %
1984 %                                                                             %
1985 %                                                                             %
1986 %                                                                             %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 %
1989 %  QueryColorDatabase() returns the red, green, blue, and opacity intensities
1990 %  for a given color name.
1991 %
1992 %  The format of the QueryColorDatabase method is:
1993 %
1994 %      MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
1995 %        ExceptionInfo *exception)
1996 %
1997 %  A description of each parameter follows:
1998 %
1999 %    o name: the color name (e.g. white, blue, yellow).
2000 %
2001 %    o color: the red, green, blue, and opacity intensities values of the
2002 %      named color in this structure.
2003 %
2004 %    o exception: return any errors or warnings in this structure.
2005 %
2006 */
2007
2008 static inline double MagickMin(const double x,const double y)
2009 {
2010   if (x < y)
2011     return(x);
2012   return(y);
2013 }
2014
2015 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
2016   PixelPacket *color,ExceptionInfo *exception)
2017 {
2018   MagickBooleanType
2019     status;
2020
2021   MagickPixelPacket
2022     pixel;
2023
2024   status=QueryMagickColor(name,&pixel,exception);
2025   color->opacity=RoundToQuantum(pixel.opacity);
2026   if (pixel.colorspace == CMYKColorspace)
2027     {
2028       color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
2029         QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
2030         pixel.index)+pixel.index))));
2031       color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
2032         QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
2033         pixel.index)+pixel.index))));
2034       color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
2035         QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
2036         pixel.index)+pixel.index))));
2037       return(status);
2038     }
2039   color->red=RoundToQuantum(pixel.red);
2040   color->green=RoundToQuantum(pixel.green);
2041   color->blue=RoundToQuantum(pixel.blue);
2042   return(status);
2043 }
2044 \f
2045 /*
2046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2047 %                                                                             %
2048 %                                                                             %
2049 %                                                                             %
2050 %  Q u e r y C o l o r n a m e                                                %
2051 %                                                                             %
2052 %                                                                             %
2053 %                                                                             %
2054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2055 %
2056 %  QueryColorname() returns a named color for the given color intensity.  If
2057 %  an exact match is not found, a rgb() color is returned instead.
2058 %
2059 %  The format of the QueryColorname method is:
2060 %
2061 %      MagickBooleanType QueryColorname(const Image *image,
2062 %        const PixelPacket *color,const ComplianceType compliance,char *name,
2063 %        ExceptionInfo *exception)
2064 %
2065 %  A description of each parameter follows.
2066 %
2067 %    o image: the image.
2068 %
2069 %    o color: the color intensities.
2070 %
2071 %    o compliance: Adhere to this color standard: SVG, X11, or XPM.
2072 %
2073 %    o name: Return the color name or hex value.
2074 %
2075 %    o exception: return any errors or warnings in this structure.
2076 %
2077 */
2078 MagickExport MagickBooleanType QueryColorname(const Image *image,
2079   const PixelPacket *color,const ComplianceType compliance,char *name,
2080   ExceptionInfo *exception)
2081 {
2082   MagickPixelPacket
2083     pixel;
2084
2085   GetMagickPixelPacket(image,&pixel);
2086   SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
2087   return(QueryMagickColorname(image,&pixel,compliance,name,exception));
2088 }
2089 \f
2090 /*
2091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2092 %                                                                             %
2093 %                                                                             %
2094 %                                                                             %
2095 %   Q u e r y M a g i c k C o l o r                                           %
2096 %                                                                             %
2097 %                                                                             %
2098 %                                                                             %
2099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100 %
2101 %  QueryMagickColor() returns the red, green, blue, and opacity intensities
2102 %  for a given color name.
2103 %
2104 %  The format of the QueryMagickColor method is:
2105 %
2106 %      MagickBooleanType QueryMagickColor(const char *name,
2107 %        MagickPixelPacket *color,ExceptionInfo *exception)
2108 %
2109 %  A description of each parameter follows:
2110 %
2111 %    o name: the color name (e.g. white, blue, yellow).
2112 %
2113 %    o color: the red, green, blue, and opacity intensities values of the
2114 %      named color in this structure.
2115 %
2116 %    o exception: return any errors or warnings in this structure.
2117 %
2118 */
2119 MagickExport MagickBooleanType QueryMagickColor(const char *name,
2120   MagickPixelPacket *color,ExceptionInfo *exception)
2121 {
2122   GeometryInfo
2123     geometry_info;
2124
2125   long
2126     type;
2127
2128   MagickRealType
2129     scale;
2130
2131   MagickStatusType
2132     flags;
2133
2134   register const ColorInfo
2135     *p;
2136
2137   register long
2138     i;
2139
2140   /*
2141     Initialize color return value.
2142   */
2143   assert(name != (const char *) NULL);
2144   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
2145   assert(color != (MagickPixelPacket *) NULL);
2146   GetMagickPixelPacket((Image *) NULL,color);
2147   if ((name == (char *) NULL) || (*name == '\0'))
2148     name=BackgroundColor;
2149   while (isspace((int) ((unsigned char) *name)) != 0)
2150     name++;
2151   if (*name == '#')
2152     {
2153       char
2154         c;
2155
2156       LongPixelPacket
2157         pixel;
2158
2159       QuantumAny
2160         range;
2161
2162       unsigned long
2163         depth,
2164         n;
2165
2166       /*
2167         Parse hex color.
2168       */
2169       (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
2170       name++;
2171       for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
2172       if ((n % 3) == 0)
2173         {
2174           do
2175           {
2176             pixel.red=pixel.green;
2177             pixel.green=pixel.blue;
2178             pixel.blue=0;
2179             for (i=(long) (n/3-1); i >= 0; i--)
2180             {
2181               c=(*name++);
2182               pixel.blue<<=4;
2183               if ((c >= '0') && (c <= '9'))
2184                 pixel.blue|=(int) (c-'0');
2185               else
2186                 if ((c >= 'A') && (c <= 'F'))
2187                   pixel.blue|=(int) c-((int) 'A'-10);
2188                 else
2189                   if ((c >= 'a') && (c <= 'f'))
2190                     pixel.blue|=(int) c-((int) 'a'-10);
2191                   else
2192                     return(MagickFalse);
2193             }
2194           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
2195           depth=4*(n/3);
2196         }
2197       else
2198         {
2199           if ((n % 4) != 0)
2200             {
2201               (void) ThrowMagickException(exception,GetMagickModule(),
2202                 OptionWarning,"UnrecognizedColor","`%s'",name);
2203               return(MagickFalse);
2204             }
2205           do
2206           {
2207             pixel.red=pixel.green;
2208             pixel.green=pixel.blue;
2209             pixel.blue=pixel.opacity;
2210             pixel.opacity=0;
2211             for (i=(long) (n/4-1); i >= 0; i--)
2212             {
2213               c=(*name++);
2214               pixel.opacity<<=4;
2215               if ((c >= '0') && (c <= '9'))
2216                 pixel.opacity|=(int) (c-'0');
2217               else
2218                 if ((c >= 'A') && (c <= 'F'))
2219                   pixel.opacity|=(int) c-((int) 'A'-10);
2220                 else
2221                   if ((c >= 'a') && (c <= 'f'))
2222                     pixel.opacity|=(int) c-((int) 'a'-10);
2223                   else
2224                     return(MagickFalse);
2225             }
2226           } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
2227           depth=4*(n/4);
2228         }
2229       color->colorspace=RGBColorspace;
2230       color->matte=MagickFalse;
2231       range=GetQuantumRange(depth);
2232       color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
2233       color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
2234       color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
2235       color->opacity=(MagickRealType) OpaqueOpacity;
2236       if ((n % 3) != 0)
2237         {
2238           color->matte=MagickTrue;
2239           color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
2240             pixel.opacity,range));
2241         }
2242       color->index=0.0;
2243       return(MagickTrue);
2244     }
2245   if (strchr(name,'(') != (char *) NULL)
2246     {
2247       char
2248         colorspace[MaxTextExtent];
2249
2250       /*
2251         Parse color of the form rgb(100,255,0).
2252       */
2253       (void) CopyMagickString(colorspace,name,MaxTextExtent);
2254       for (i=0; colorspace[i] != '\0'; i++)
2255         if (colorspace[i] == '(')
2256           break;
2257       colorspace[i--]='\0';
2258       LocaleLower(colorspace);
2259       color->matte=MagickFalse;
2260       if ((i > 0) && (colorspace[i] == 'a'))
2261         {
2262           colorspace[i]='\0';
2263           color->matte=MagickTrue;
2264         }
2265       type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
2266       if (type < 0)
2267         {
2268           (void) ThrowMagickException(exception,GetMagickModule(),
2269             OptionWarning,"UnrecognizedColor","`%s'",name);
2270           return(MagickFalse);
2271         }
2272       color->colorspace=(ColorspaceType) type;
2273       SetGeometryInfo(&geometry_info);
2274       flags=ParseGeometry(name+i+1,&geometry_info);
2275       scale=(MagickRealType) ScaleCharToQuantum(1);
2276       if ((flags & PercentValue) != 0)
2277         scale=(MagickRealType) (QuantumRange/100.0);
2278       if ((flags & RhoValue) != 0)
2279         color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
2280       if ((flags & SigmaValue) != 0)
2281         color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
2282       if ((flags & XiValue) != 0)
2283         color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
2284       color->opacity=(MagickRealType) OpaqueOpacity;
2285       if ((flags & PsiValue) != 0)
2286         {
2287           if (color->colorspace == CMYKColorspace)
2288             color->index=(MagickRealType) RoundToQuantum(scale*
2289               geometry_info.psi);
2290           else
2291             if (color->matte != MagickFalse)
2292               color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2293                 (QuantumRange-QuantumRange*geometry_info.psi));
2294         }
2295       if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
2296         color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2297           (QuantumRange-QuantumRange*geometry_info.chi));
2298       if (LocaleCompare(colorspace,"gray") == 0)
2299         {
2300           color->green=color->red;
2301           color->blue=color->red;
2302           if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
2303             color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
2304               (QuantumRange-QuantumRange*geometry_info.sigma));
2305         }
2306       if ((LocaleCompare(colorspace,"HSB") == 0) ||
2307           (LocaleCompare(colorspace,"HSL") == 0) ||
2308           (LocaleCompare(colorspace,"HWB") == 0))
2309         {
2310           PixelPacket
2311             pixel;
2312
2313           scale=1.0/360.0;
2314           if ((flags & PercentValue) != 0)
2315             scale=1.0/100.0;
2316           geometry_info.rho*=360.0*scale;
2317           scale=1.0/255.0;
2318           if ((flags & PercentValue) != 0)
2319             scale=1.0/100.0;
2320           geometry_info.sigma*=scale;
2321           geometry_info.xi*=scale;
2322           if (LocaleCompare(colorspace,"HSB") == 0)
2323             ConvertHSBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2324               360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2325               &pixel.green,&pixel.blue);
2326           else
2327             if (LocaleCompare(colorspace,"HSL") == 0)
2328               ConvertHSLToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2329                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2330                 &pixel.green,&pixel.blue);
2331             else
2332               ConvertHWBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
2333                 360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
2334                 &pixel.green,&pixel.blue);
2335           color->colorspace=RGBColorspace;
2336           color->red=(MagickRealType) pixel.red;
2337           color->green=(MagickRealType) pixel.green;
2338           color->blue=(MagickRealType) pixel.blue;
2339         }
2340       return(MagickTrue);
2341     }
2342   /*
2343     Parse named color.
2344   */
2345   p=GetColorInfo(name,exception);
2346   if (p == (const ColorInfo *) NULL)
2347     return(MagickFalse);
2348   color->colorspace=RGBColorspace;
2349   color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
2350   color->red=(MagickRealType) p->color.red;
2351   color->green=(MagickRealType) p->color.green;
2352   color->blue=(MagickRealType) p->color.blue;
2353   color->opacity=(MagickRealType) p->color.opacity;
2354   color->index=0.0;
2355   return(MagickTrue);
2356 }
2357 \f
2358 /*
2359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2360 %                                                                             %
2361 %                                                                             %
2362 %                                                                             %
2363 %  Q u e r y M a g i c k C o l o r n a m e                                    %
2364 %                                                                             %
2365 %                                                                             %
2366 %                                                                             %
2367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368 %
2369 %  QueryMagickColorname() returns a named color for the given color intensity.
2370 %  If an exact match is not found, a hex value is returned instead.  For
2371 %  example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
2372 %  returns #dfdfdf.
2373 %
2374 %  The format of the QueryMagickColorname method is:
2375 %
2376 %      MagickBooleanType QueryMagickColorname(const Image *image,
2377 %        const PixelPacket *color,const ComplianceType compliance,char *name,
2378 %        ExceptionInfo *exception)
2379 %
2380 %  A description of each parameter follows.
2381 %
2382 %    o image: the image.
2383 %
2384 %    o color: the color intensities.
2385 %
2386 %    o Compliance: Adhere to this color standard: SVG, X11, or XPM.
2387 %
2388 %    o name: Return the color name or hex value.
2389 %
2390 %    o exception: return any errors or warnings in this structure.
2391 %
2392 */
2393 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
2394   const MagickPixelPacket *color,const ComplianceType compliance,
2395   char *name,ExceptionInfo *exception)
2396 {
2397   MagickPixelPacket
2398     pixel;
2399
2400   MagickRealType
2401     opacity;
2402
2403   register const ColorInfo
2404     *p;
2405
2406   *name='\0';
2407   pixel=(*color);
2408   if (compliance == XPMCompliance)
2409     {
2410       pixel.matte=MagickFalse;
2411       pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
2412       GetColorTuple(&pixel,MagickTrue,name);
2413       return(MagickTrue);
2414     }
2415   GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
2416     name);
2417   (void) GetColorInfo("*",exception);
2418   ResetLinkedListIterator(color_list);
2419   opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
2420   p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
2421   while (p != (const ColorInfo *) NULL)
2422   {
2423     if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
2424          (p->color.green == color->green) && (p->color.blue == color->blue) &&
2425          (p->color.opacity == opacity))
2426       {
2427         (void) CopyMagickString(name,p->name,MaxTextExtent);
2428         break;
2429       }
2430     p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
2431   }
2432   return(MagickTrue);
2433 }