2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 % CCCC OOO L OOO RRRR %
9 % CCCC OOO LLLLL OOO R R %
12 % MagickCore Color Methods %
19 % Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
20 % dedicated to making software imaging solutions freely available. %
22 % You may not use this file except in compliance with the License. You may %
23 % obtain a copy of the License at %
25 % http://www.imagemagick.org/script/license.php %
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. %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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).
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"
72 #define ColorFilename "colors.xml"
73 #define MaxTreeDepth 8
74 #define NodesInAList 1536
80 *ColorMap = (const char *)
81 "<?xml version=\"1.0\"?>"
83 " <color name=\"none\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
84 " <color name=\"black\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11, XPM\" />"
85 " <color name=\"red\" color=\"rgb(255,0,0)\" compliance=\"SVG, X11, XPM\" />"
86 " <color name=\"magenta\" color=\"rgb(255,0,255)\" compliance=\"SVG, X11, XPM\" />"
87 " <color name=\"green\" color=\"rgb(0,128,0)\" compliance=\"SVG\" />"
88 " <color name=\"cyan\" color=\"rgb(0,255,255)\" compliance=\"SVG, X11, XPM\" />"
89 " <color name=\"blue\" color=\"rgb(0,0,255)\" compliance=\"SVG, X11, XPM\" />"
90 " <color name=\"yellow\" color=\"rgb(255,255,0)\" compliance=\"SVG, X11, XPM\" />"
91 " <color name=\"white\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
92 " <color name=\"AliceBlue\" color=\"rgb(240,248,255)\" compliance=\"SVG, X11, XPM\" />"
93 " <color name=\"AntiqueWhite\" color=\"rgb(250,235,215)\" compliance=\"SVG, X11, XPM\" />"
94 " <color name=\"aqua\" color=\"rgb(0,255,255)\" compliance=\"SVG\" />"
95 " <color name=\"aquamarine\" color=\"rgb(127,255,212)\" compliance=\"SVG, X11, XPM\" />"
96 " <color name=\"azure\" color=\"rgb(240,255,255)\" compliance=\"SVG, X11, XPM\" />"
97 " <color name=\"beige\" color=\"rgb(245,245,220)\" compliance=\"SVG, X11, XPM\" />"
98 " <color name=\"bisque\" color=\"rgb(255,228,196)\" compliance=\"SVG, X11, XPM\" />"
99 " <color name=\"BlanchedAlmond\" color=\"rgb(255,235,205)\" compliance=\"SVG, X11, XPM\" />"
100 " <color name=\"BlueViolet\" color=\"rgb(138,43,226)\" compliance=\"SVG, X11, XPM\" />"
101 " <color name=\"brown\" color=\"rgb(165,42,42)\" compliance=\"SVG, X11, XPM\" />"
102 " <color name=\"burlywood\" color=\"rgb(222,184,135)\" compliance=\"SVG, X11, XPM\" />"
103 " <color name=\"CadetBlue\" color=\"rgb(95,158,160)\" compliance=\"SVG, X11, XPM\" />"
104 " <color name=\"chartreuse\" color=\"rgb(127,255,0)\" compliance=\"SVG, X11, XPM\" />"
105 " <color name=\"chocolate\" color=\"rgb(210,105,30)\" compliance=\"SVG, X11, XPM\" />"
106 " <color name=\"coral\" color=\"rgb(255,127,80)\" compliance=\"SVG, X11, XPM\" />"
107 " <color name=\"CornflowerBlue\" color=\"rgb(100,149,237)\" compliance=\"SVG, X11, XPM\" />"
108 " <color name=\"cornsilk\" color=\"rgb(255,248,220)\" compliance=\"SVG, X11, XPM\" />"
109 " <color name=\"crimson\" color=\"rgb(220,20,60)\" compliance=\"SVG\" />"
110 " <color name=\"DarkBlue\" color=\"rgb(0,0,139)\" compliance=\"SVG, X11\" />"
111 " <color name=\"DarkCyan\" color=\"rgb(0,139,139)\" compliance=\"SVG, X11\" />"
112 " <color name=\"DarkGoldenrod\" color=\"rgb(184,134,11)\" compliance=\"SVG, X11, XPM\" />"
113 " <color name=\"DarkGray\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
114 " <color name=\"DarkGreen\" color=\"rgb(0,100,0)\" compliance=\"SVG, X11, XPM\" />"
115 " <color name=\"DarkGrey\" color=\"rgb(169,169,169)\" compliance=\"SVG, X11\" />"
116 " <color name=\"DarkKhaki\" color=\"rgb(189,183,107)\" compliance=\"SVG, X11, XPM\" />"
117 " <color name=\"DarkMagenta\" color=\"rgb(139,0,139)\" compliance=\"SVG, X11\" />"
118 " <color name=\"DarkOliveGreen\" color=\"rgb(85,107,47)\" compliance=\"SVG, X11, XPM\" />"
119 " <color name=\"DarkOrange\" color=\"rgb(255,140,0)\" compliance=\"SVG, X11, XPM\" />"
120 " <color name=\"DarkOrchid\" color=\"rgb(153,50,204)\" compliance=\"SVG, X11, XPM\" />"
121 " <color name=\"DarkRed\" color=\"rgb(139,0,0)\" compliance=\"SVG, X11\" />"
122 " <color name=\"DarkSalmon\" color=\"rgb(233,150,122)\" compliance=\"SVG, X11, XPM\" />"
123 " <color name=\"DarkSeaGreen\" color=\"rgb(143,188,143)\" compliance=\"SVG, X11, XPM\" />"
124 " <color name=\"DarkSlateBlue\" color=\"rgb(72,61,139)\" compliance=\"SVG, X11, XPM\" />"
125 " <color name=\"DarkSlateGray\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11, XPM\" />"
126 " <color name=\"DarkSlateGrey\" color=\"rgb(47,79,79)\" compliance=\"SVG, X11\" />"
127 " <color name=\"DarkTurquoise\" color=\"rgb(0,206,209)\" compliance=\"SVG, X11, XPM\" />"
128 " <color name=\"DarkViolet\" color=\"rgb(148,0,211)\" compliance=\"SVG, X11, XPM\" />"
129 " <color name=\"DeepPink\" color=\"rgb(255,20,147)\" compliance=\"SVG, X11, XPM\" />"
130 " <color name=\"DeepSkyBlue\" color=\"rgb(0,191,255)\" compliance=\"SVG, X11, XPM\" />"
131 " <color name=\"DimGray\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11, XPM\" />"
132 " <color name=\"DimGrey\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
133 " <color name=\"DodgerBlue\" color=\"rgb(30,144,255)\" compliance=\"SVG, X11, XPM\" />"
134 " <color name=\"firebrick\" color=\"rgb(178,34,34)\" compliance=\"SVG, X11, XPM\" />"
135 " <color name=\"FloralWhite\" color=\"rgb(255,250,240)\" compliance=\"SVG, X11, XPM\" />"
136 " <color name=\"ForestGreen\" color=\"rgb(34,139,34)\" compliance=\"SVG, X11, XPM\" />"
137 " <color name=\"fractal\" color=\"rgb(128,128,128)\" compliance=\"SVG\" />"
138 " <color name=\"fuchsia\" color=\"rgb(255,0,255)\" compliance=\"SVG\" />"
139 " <color name=\"gainsboro\" color=\"rgb(220,220,220)\" compliance=\"SVG, X11, XPM\" />"
140 " <color name=\"GhostWhite\" color=\"rgb(248,248,255)\" compliance=\"SVG, X11, XPM\" />"
141 " <color name=\"gold\" color=\"rgb(255,215,0)\" compliance=\"X11, XPM\" />"
142 " <color name=\"goldenrod\" color=\"rgb(218,165,32)\" compliance=\"SVG, X11, XPM\" />"
143 " <color name=\"gray\" color=\"rgb(126,126,126)\" compliance=\"SVG\" />"
144 " <color name=\"gray74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
145 " <color name=\"gray100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
146 " <color name=\"grey\" color=\"rgb(190,190,190)\" compliance=\"SVG, X11\" />"
147 " <color name=\"grey0\" color=\"rgb(0,0,0)\" compliance=\"SVG, X11\" />"
148 " <color name=\"grey1\" color=\"rgb(3,3,3)\" compliance=\"SVG, X11\" />"
149 " <color name=\"grey10\" color=\"rgb(26,26,26)\" compliance=\"SVG, X11\" />"
150 " <color name=\"grey100\" color=\"rgb(255,255,255)\" compliance=\"SVG, X11\" />"
151 " <color name=\"grey11\" color=\"rgb(28,28,28)\" compliance=\"SVG, X11\" />"
152 " <color name=\"grey12\" color=\"rgb(31,31,31)\" compliance=\"SVG, X11\" />"
153 " <color name=\"grey13\" color=\"rgb(33,33,33)\" compliance=\"SVG, X11\" />"
154 " <color name=\"grey14\" color=\"rgb(36,36,36)\" compliance=\"SVG, X11\" />"
155 " <color name=\"grey15\" color=\"rgb(38,38,38)\" compliance=\"SVG, X11\" />"
156 " <color name=\"grey16\" color=\"rgb(41,41,41)\" compliance=\"SVG, X11\" />"
157 " <color name=\"grey17\" color=\"rgb(43,43,43)\" compliance=\"SVG, X11\" />"
158 " <color name=\"grey18\" color=\"rgb(45,45,45)\" compliance=\"SVG, X11\" />"
159 " <color name=\"grey19\" color=\"rgb(48,48,48)\" compliance=\"SVG, X11\" />"
160 " <color name=\"grey2\" color=\"rgb(5,5,5)\" compliance=\"SVG, X11\" />"
161 " <color name=\"grey20\" color=\"rgb(51,51,51)\" compliance=\"SVG, X11\" />"
162 " <color name=\"grey21\" color=\"rgb(54,54,54)\" compliance=\"SVG, X11\" />"
163 " <color name=\"grey22\" color=\"rgb(56,56,56)\" compliance=\"SVG, X11\" />"
164 " <color name=\"grey23\" color=\"rgb(59,59,59)\" compliance=\"SVG, X11\" />"
165 " <color name=\"grey24\" color=\"rgb(61,61,61)\" compliance=\"SVG, X11\" />"
166 " <color name=\"grey25\" color=\"rgb(64,64,64)\" compliance=\"SVG, X11\" />"
167 " <color name=\"grey26\" color=\"rgb(66,66,66)\" compliance=\"SVG, X11\" />"
168 " <color name=\"grey27\" color=\"rgb(69,69,69)\" compliance=\"SVG, X11\" />"
169 " <color name=\"grey28\" color=\"rgb(71,71,71)\" compliance=\"SVG, X11\" />"
170 " <color name=\"grey29\" color=\"rgb(74,74,74)\" compliance=\"SVG, X11\" />"
171 " <color name=\"grey3\" color=\"rgb(8,8,8)\" compliance=\"SVG, X11\" />"
172 " <color name=\"grey30\" color=\"rgb(77,77,77)\" compliance=\"SVG, X11\" />"
173 " <color name=\"grey31\" color=\"rgb(79,79,79)\" compliance=\"SVG, X11\" />"
174 " <color name=\"grey32\" color=\"rgb(82,82,82)\" compliance=\"SVG, X11\" />"
175 " <color name=\"grey33\" color=\"rgb(84,84,84)\" compliance=\"SVG, X11\" />"
176 " <color name=\"grey34\" color=\"rgb(87,87,87)\" compliance=\"SVG, X11\" />"
177 " <color name=\"grey35\" color=\"rgb(89,89,89)\" compliance=\"SVG, X11\" />"
178 " <color name=\"grey36\" color=\"rgb(92,92,92)\" compliance=\"SVG, X11\" />"
179 " <color name=\"grey37\" color=\"rgb(94,94,94)\" compliance=\"SVG, X11\" />"
180 " <color name=\"grey38\" color=\"rgb(97,97,97)\" compliance=\"SVG, X11\" />"
181 " <color name=\"grey39\" color=\"rgb(99,99,99)\" compliance=\"SVG, X11\" />"
182 " <color name=\"grey4\" color=\"rgb(10,10,10)\" compliance=\"SVG, X11\" />"
183 " <color name=\"grey40\" color=\"rgb(102,102,102)\" compliance=\"SVG, X11\" />"
184 " <color name=\"grey41\" color=\"rgb(105,105,105)\" compliance=\"SVG, X11\" />"
185 " <color name=\"grey42\" color=\"rgb(107,107,107)\" compliance=\"SVG, X11\" />"
186 " <color name=\"grey43\" color=\"rgb(110,110,110)\" compliance=\"SVG, X11\" />"
187 " <color name=\"grey44\" color=\"rgb(112,112,112)\" compliance=\"SVG, X11\" />"
188 " <color name=\"grey45\" color=\"rgb(115,115,115)\" compliance=\"SVG, X11\" />"
189 " <color name=\"grey45\" color=\"rgb(117,117,117)\" compliance=\"SVG, X11\" />"
190 " <color name=\"grey47\" color=\"rgb(120,120,120)\" compliance=\"SVG, X11\" />"
191 " <color name=\"grey48\" color=\"rgb(122,122,122)\" compliance=\"SVG, X11\" />"
192 " <color name=\"grey49\" color=\"rgb(125,125,125)\" compliance=\"SVG, X11\" />"
193 " <color name=\"grey5\" color=\"rgb(13,13,13)\" compliance=\"SVG, X11\" />"
194 " <color name=\"grey50\" color=\"rgb(50%,50%,50%)\" compliance=\"SVG, X11\" />"
195 " <color name=\"grey51\" color=\"rgb(130,130,130)\" compliance=\"SVG, X11\" />"
196 " <color name=\"grey52\" color=\"rgb(133,133,133)\" compliance=\"SVG, X11\" />"
197 " <color name=\"grey53\" color=\"rgb(135,135,135)\" compliance=\"SVG, X11\" />"
198 " <color name=\"grey54\" color=\"rgb(138,138,138)\" compliance=\"SVG, X11\" />"
199 " <color name=\"grey55\" color=\"rgb(140,140,140)\" compliance=\"SVG, X11\" />"
200 " <color name=\"grey56\" color=\"rgb(143,143,143)\" compliance=\"SVG, X11\" />"
201 " <color name=\"grey57\" color=\"rgb(145,145,145)\" compliance=\"SVG, X11\" />"
202 " <color name=\"grey58\" color=\"rgb(148,148,148)\" compliance=\"SVG, X11\" />"
203 " <color name=\"grey59\" color=\"rgb(150,150,150)\" compliance=\"SVG, X11\" />"
204 " <color name=\"grey6\" color=\"rgb(15,15,15)\" compliance=\"SVG, X11\" />"
205 " <color name=\"grey60\" color=\"rgb(153,153,153)\" compliance=\"SVG, X11\" />"
206 " <color name=\"grey61\" color=\"rgb(156,156,156)\" compliance=\"SVG, X11\" />"
207 " <color name=\"grey62\" color=\"rgb(158,158,158)\" compliance=\"SVG, X11\" />"
208 " <color name=\"grey63\" color=\"rgb(161,161,161)\" compliance=\"SVG, X11\" />"
209 " <color name=\"grey64\" color=\"rgb(163,163,163)\" compliance=\"SVG, X11\" />"
210 " <color name=\"grey65\" color=\"rgb(166,166,166)\" compliance=\"SVG, X11\" />"
211 " <color name=\"grey66\" color=\"rgb(168,168,168)\" compliance=\"SVG, X11\" />"
212 " <color name=\"grey67\" color=\"rgb(171,171,171)\" compliance=\"SVG, X11\" />"
213 " <color name=\"grey68\" color=\"rgb(173,173,173)\" compliance=\"SVG, X11\" />"
214 " <color name=\"grey69\" color=\"rgb(176,176,176)\" compliance=\"SVG, X11\" />"
215 " <color name=\"grey7\" color=\"rgb(18,18,18)\" compliance=\"SVG, X11\" />"
216 " <color name=\"grey70\" color=\"rgb(179,179,179)\" compliance=\"SVG, X11\" />"
217 " <color name=\"grey71\" color=\"rgb(181,181,181)\" compliance=\"SVG, X11\" />"
218 " <color name=\"grey72\" color=\"rgb(184,184,184)\" compliance=\"SVG, X11\" />"
219 " <color name=\"grey73\" color=\"rgb(186,186,186)\" compliance=\"SVG, X11\" />"
220 " <color name=\"grey74\" color=\"rgb(189,189,189)\" compliance=\"SVG, X11\" />"
221 " <color name=\"grey75\" color=\"rgb(191,191,191)\" compliance=\"SVG, X11\" />"
222 " <color name=\"grey76\" color=\"rgb(194,194,194)\" compliance=\"SVG, X11\" />"
223 " <color name=\"grey77\" color=\"rgb(196,196,196)\" compliance=\"SVG, X11\" />"
224 " <color name=\"grey78\" color=\"rgb(199,199,199)\" compliance=\"SVG, X11\" />"
225 " <color name=\"grey79\" color=\"rgb(201,201,201)\" compliance=\"SVG, X11\" />"
226 " <color name=\"grey8\" color=\"rgb(20,20,20)\" compliance=\"SVG, X11\" />"
227 " <color name=\"grey80\" color=\"rgb(204,204,204)\" compliance=\"SVG, X11\" />"
228 " <color name=\"grey81\" color=\"rgb(207,207,207)\" compliance=\"SVG, X11\" />"
229 " <color name=\"grey82\" color=\"rgb(209,209,209)\" compliance=\"SVG, X11\" />"
230 " <color name=\"grey83\" color=\"rgb(212,212,212)\" compliance=\"SVG, X11\" />"
231 " <color name=\"grey84\" color=\"rgb(214,214,214)\" compliance=\"SVG, X11\" />"
232 " <color name=\"grey85\" color=\"rgb(217,217,217)\" compliance=\"SVG, X11\" />"
233 " <color name=\"grey86\" color=\"rgb(219,219,219)\" compliance=\"SVG, X11\" />"
234 " <color name=\"grey87\" color=\"rgb(222,222,222)\" compliance=\"SVG, X11\" />"
235 " <color name=\"grey88\" color=\"rgb(224,224,224)\" compliance=\"SVG, X11\" />"
236 " <color name=\"grey89\" color=\"rgb(227,227,227)\" compliance=\"SVG, X11\" />"
237 " <color name=\"grey9\" color=\"rgb(23,23,23)\" compliance=\"SVG, X11\" />"
238 " <color name=\"grey90\" color=\"rgb(229,229,229)\" compliance=\"SVG, X11\" />"
239 " <color name=\"grey91\" color=\"rgb(232,232,232)\" compliance=\"SVG, X11\" />"
240 " <color name=\"grey92\" color=\"rgb(235,235,235)\" compliance=\"SVG, X11\" />"
241 " <color name=\"grey93\" color=\"rgb(237,237,237)\" compliance=\"SVG, X11\" />"
242 " <color name=\"grey94\" color=\"rgb(240,240,240)\" compliance=\"SVG, X11\" />"
243 " <color name=\"grey95\" color=\"rgb(242,242,242)\" compliance=\"SVG, X11\" />"
244 " <color name=\"grey96\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11\" />"
245 " <color name=\"grey97\" color=\"rgb(247,247,247)\" compliance=\"SVG, X11\" />"
246 " <color name=\"grey98\" color=\"rgb(250,250,250)\" compliance=\"SVG, X11\" />"
247 " <color name=\"grey99\" color=\"rgb(252,252,252)\" compliance=\"SVG, X11\" />"
248 " <color name=\"honeydew\" color=\"rgb(240,255,240)\" compliance=\"SVG, X11, XPM\" />"
249 " <color name=\"HotPink\" color=\"rgb(255,105,180)\" compliance=\"SVG, X11, XPM\" />"
250 " <color name=\"IndianRed\" color=\"rgb(205,92,92)\" compliance=\"SVG, X11, XPM\" />"
251 " <color name=\"indigo\" color=\"rgb(75,0,130)\" compliance=\"SVG\" />"
252 " <color name=\"ivory\" color=\"rgb(255,255,240)\" compliance=\"SVG, X11, XPM\" />"
253 " <color name=\"khaki\" color=\"rgb(240,230,140)\" compliance=\"SVG, X11, XPM\" />"
254 " <color name=\"lavender\" color=\"rgb(230,230,250)\" compliance=\"SVG, X11, XPM\" />"
255 " <color name=\"LavenderBlush\" color=\"rgb(255,240,245)\" compliance=\"SVG, X11, XPM\" />"
256 " <color name=\"LawnGreen\" color=\"rgb(124,252,0)\" compliance=\"SVG, X11, XPM\" />"
257 " <color name=\"LemonChiffon\" color=\"rgb(255,250,205)\" compliance=\"SVG, X11, XPM\" />"
258 " <color name=\"LightBlue\" color=\"rgb(173,216,230)\" compliance=\"SVG, X11, XPM\" />"
259 " <color name=\"LightCoral\" color=\"rgb(240,128,128)\" compliance=\"SVG, X11, XPM\" />"
260 " <color name=\"LightCyan\" color=\"rgb(224,255,255)\" compliance=\"SVG, X11, XPM\" />"
261 " <color name=\"LightGoldenrodYellow\" color=\"rgb(250,250,210)\" compliance=\"SVG, X11, XPM\" />"
262 " <color name=\"LightGray\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11, XPM\" />"
263 " <color name=\"LightGreen\" color=\"rgb(144,238,144)\" compliance=\"SVG, X11\" />"
264 " <color name=\"LightGrey\" color=\"rgb(211,211,211)\" compliance=\"SVG, X11\" />"
265 " <color name=\"LightPink\" color=\"rgb(255,182,193)\" compliance=\"SVG, X11, XPM\" />"
266 " <color name=\"LightSalmon\" color=\"rgb(255,160,122)\" compliance=\"SVG, X11, XPM\" />"
267 " <color name=\"LightSeaGreen\" color=\"rgb(32,178,170)\" compliance=\"SVG, X11, XPM\" />"
268 " <color name=\"LightSkyBlue\" color=\"rgb(135,206,250)\" compliance=\"SVG, X11, XPM\" />"
269 " <color name=\"LightSlateGray\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11, XPM\" />"
270 " <color name=\"LightSlateGrey\" color=\"rgb(119,136,153)\" compliance=\"SVG, X11\" />"
271 " <color name=\"LightSteelBlue\" color=\"rgb(176,196,222)\" compliance=\"SVG, X11, XPM\" />"
272 " <color name=\"LightYellow\" color=\"rgb(255,255,224)\" compliance=\"SVG, X11, XPM\" />"
273 " <color name=\"lime\" color=\"rgb(0,255,0)\" compliance=\"SVG\" />"
274 " <color name=\"LimeGreen\" color=\"rgb(50,205,50)\" compliance=\"SVG, X11, XPM\" />"
275 " <color name=\"linen\" color=\"rgb(250,240,230)\" compliance=\"SVG, X11, XPM\" />"
276 " <color name=\"maroon\" color=\"rgb(128,0,0)\" compliance=\"SVG\" />"
277 " <color name=\"MediumAquamarine\" color=\"rgb(102,205,170)\" compliance=\"SVG, X11, XPM\" />"
278 " <color name=\"MediumBlue\" color=\"rgb(0,0,205)\" compliance=\"SVG, X11, XPM\" />"
279 " <color name=\"MediumOrchid\" color=\"rgb(186,85,211)\" compliance=\"SVG, X11, XPM\" />"
280 " <color name=\"MediumPurple\" color=\"rgb(147,112,219)\" compliance=\"SVG, X11, XPM\" />"
281 " <color name=\"MediumSeaGreen\" color=\"rgb(60,179,113)\" compliance=\"SVG, X11, XPM\" />"
282 " <color name=\"MediumSlateBlue\" color=\"rgb(123,104,238)\" compliance=\"SVG, X11, XPM\" />"
283 " <color name=\"MediumSpringGreen\" color=\"rgb(0,250,154)\" compliance=\"SVG, X11, XPM\" />"
284 " <color name=\"MediumTurquoise\" color=\"rgb(72,209,204)\" compliance=\"SVG, X11, XPM\" />"
285 " <color name=\"MediumVioletRed\" color=\"rgb(199,21,133)\" compliance=\"SVG, X11, XPM\" />"
286 " <color name=\"MidnightBlue\" color=\"rgb(25,25,112)\" compliance=\"SVG, X11, XPM\" />"
287 " <color name=\"MintCream\" color=\"rgb(245,255,250)\" compliance=\"SVG, X11, XPM\" />"
288 " <color name=\"MistyRose\" color=\"rgb(255,228,225)\" compliance=\"SVG, X11, XPM\" />"
289 " <color name=\"moccasin\" color=\"rgb(255,228,181)\" compliance=\"SVG, X11, XPM\" />"
290 " <color name=\"NavajoWhite\" color=\"rgb(255,222,173)\" compliance=\"SVG, X11, XPM\" />"
291 " <color name=\"navy\" color=\"rgb(0,0,128)\" compliance=\"SVG, X11, XPM\" />"
292 " <color name=\"matte\" color=\"rgb(0,0,0,0)\" compliance=\"SVG\" />"
293 " <color name=\"OldLace\" color=\"rgb(253,245,230)\" compliance=\"SVG, X11, XPM\" />"
294 " <color name=\"olive\" color=\"rgb(128,128,0)\" compliance=\"SVG\" />"
295 " <color name=\"OliveDrab\" color=\"rgb(107,142,35)\" compliance=\"SVG, X11, XPM\" />"
296 " <color name=\"opaque\" color=\"rgb(0,0,0)\" compliance=\"SVG\" />"
297 " <color name=\"orange\" color=\"rgb(255,165,0)\" compliance=\"SVG, X11, XPM\" />"
298 " <color name=\"OrangeRed\" color=\"rgb(255,69,0)\" compliance=\"SVG, X11, XPM\" />"
299 " <color name=\"orchid\" color=\"rgb(218,112,214)\" compliance=\"SVG, X11, XPM\" />"
300 " <color name=\"PaleGoldenrod\" color=\"rgb(238,232,170)\" compliance=\"SVG, X11, XPM\" />"
301 " <color name=\"PaleGreen\" color=\"rgb(152,251,152)\" compliance=\"SVG, X11, XPM\" />"
302 " <color name=\"PaleTurquoise\" color=\"rgb(175,238,238)\" compliance=\"SVG, X11, XPM\" />"
303 " <color name=\"PaleVioletRed\" color=\"rgb(219,112,147)\" compliance=\"SVG, X11, XPM\" />"
304 " <color name=\"PapayaWhip\" color=\"rgb(255,239,213)\" compliance=\"SVG, X11, XPM\" />"
305 " <color name=\"PeachPuff\" color=\"rgb(255,218,185)\" compliance=\"SVG, X11, XPM\" />"
306 " <color name=\"peru\" color=\"rgb(205,133,63)\" compliance=\"SVG, X11, XPM\" />"
307 " <color name=\"pink\" color=\"rgb(255,192,203)\" compliance=\"SVG, X11, XPM\" />"
308 " <color name=\"plum\" color=\"rgb(221,160,221)\" compliance=\"SVG, X11, XPM\" />"
309 " <color name=\"PowderBlue\" color=\"rgb(176,224,230)\" compliance=\"SVG, X11, XPM\" />"
310 " <color name=\"purple\" color=\"rgb(128,0,128)\" compliance=\"SVG\" />"
311 " <color name=\"RosyBrown\" color=\"rgb(188,143,143)\" compliance=\"SVG, X11, XPM\" />"
312 " <color name=\"RoyalBlue\" color=\"rgb(65,105,225)\" compliance=\"SVG, X11, XPM\" />"
313 " <color name=\"SaddleBrown\" color=\"rgb(139,69,19)\" compliance=\"SVG, X11, XPM\" />"
314 " <color name=\"salmon\" color=\"rgb(250,128,114)\" compliance=\"SVG, X11, XPM\" />"
315 " <color name=\"SandyBrown\" color=\"rgb(244,164,96)\" compliance=\"SVG, X11, XPM\" />"
316 " <color name=\"SeaGreen\" color=\"rgb(45,139,87)\" compliance=\"SVG, X11, XPM\" />"
317 " <color name=\"seashell\" color=\"rgb(255,245,238)\" compliance=\"SVG, X11, XPM\" />"
318 " <color name=\"sienna\" color=\"rgb(160,82,45)\" compliance=\"SVG, X11, XPM\" />"
319 " <color name=\"silver\" color=\"rgb(192,192,192)\" compliance=\"SVG\" />"
320 " <color name=\"SkyBlue\" color=\"rgb(135,206,235)\" compliance=\"SVG, X11, XPM\" />"
321 " <color name=\"SlateBlue\" color=\"rgb(106,90,205)\" compliance=\"SVG, X11, XPM\" />"
322 " <color name=\"SlateGray\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11, XPM\" />"
323 " <color name=\"SlateGrey\" color=\"rgb(112,128,144)\" compliance=\"SVG, X11\" />"
324 " <color name=\"snow\" color=\"rgb(255,250,250)\" compliance=\"SVG, X11, XPM\" />"
325 " <color name=\"SpringGreen\" color=\"rgb(0,255,127)\" compliance=\"SVG, X11, XPM\" />"
326 " <color name=\"SteelBlue\" color=\"rgb(70,130,180)\" compliance=\"SVG, X11, XPM\" />"
327 " <color name=\"tan\" color=\"rgb(210,180,140)\" compliance=\"SVG, X11, XPM\" />"
328 " <color name=\"teal\" color=\"rgb(0,128,128)\" compliance=\"SVG\" />"
329 " <color name=\"thistle\" color=\"rgb(216,191,216)\" compliance=\"SVG, X11, XPM\" />"
330 " <color name=\"tomato\" color=\"rgb(255,99,71)\" compliance=\"SVG, X11, XPM\" />"
331 " <color name=\"transparent\" color=\"rgba(0,0,0,0)\" compliance=\"SVG\" />"
332 " <color name=\"turquoise\" color=\"rgb(64,224,208)\" compliance=\"SVG, X11, XPM\" />"
333 " <color name=\"violet\" color=\"rgb(238,130,238)\" compliance=\"SVG, X11, XPM\" />"
334 " <color name=\"wheat\" color=\"rgb(245,222,179)\" compliance=\"SVG, X11, XPM\" />"
335 " <color name=\"WhiteSmoke\" color=\"rgb(245,245,245)\" compliance=\"SVG, X11, XPM\" />"
336 " <color name=\"YellowGreen\" color=\"rgb(154,205,50)\" compliance=\"SVG, X11, XPM\" />"
340 Typedef declarations.
342 typedef struct _NodeInfo
357 typedef struct _Nodes
366 typedef struct _CubeInfo
389 static LinkedListInfo
390 *color_list = (LinkedListInfo *) NULL;
393 *color_semaphore = (SemaphoreInfo *) NULL;
395 static volatile MagickBooleanType
396 instantiate_color = MagickFalse;
399 Forward declarations.
405 *GetNodeInfo(CubeInfo *,const unsigned long);
407 static MagickBooleanType
408 InitializeColorList(ExceptionInfo *),
409 LoadColorLists(const char *,ExceptionInfo *);
412 DestroyColorCube(const Image *,NodeInfo *);
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 + C l a s s i f y I m a g e C o l o r s %
423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 % ClassifyImageColors() builds a populated CubeInfo tree for the specified
426 % image. The returned tree should be deallocated using DestroyCubeInfo()
427 % once it is no longer needed.
429 % The format of the ClassifyImageColors() method is:
431 % CubeInfo *ClassifyImageColors(const Image *image,
432 % ExceptionInfo *exception)
434 % A description of each parameter follows.
436 % o image: the image.
438 % o exception: return any errors or warnings in this structure.
442 static inline unsigned long ColorToNodeId(const Image *image,
443 const MagickPixelPacket *pixel,unsigned long index)
449 ((ScaleQuantumToChar(RoundToQuantum(pixel->red)) >> index) & 0x01) |
450 ((ScaleQuantumToChar(RoundToQuantum(pixel->green)) >> index) & 0x01) << 1 |
451 ((ScaleQuantumToChar(RoundToQuantum(pixel->blue)) >> index) & 0x01) << 2);
452 if (image->matte != MagickFalse)
453 id|=((ScaleQuantumToChar(RoundToQuantum(pixel->opacity)) >> index) &
458 static CubeInfo *ClassifyImageColors(const Image *image,
459 ExceptionInfo *exception)
461 #define EvaluateImageTag " Compute image colors... "
479 register const IndexPacket
482 register const PixelPacket
489 register unsigned long
498 Initialize color description tree.
500 assert(image != (const Image *) NULL);
501 assert(image->signature == MagickSignature);
502 if (image->debug != MagickFalse)
503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
504 cube_info=GetCubeInfo();
505 if (cube_info == (CubeInfo *) NULL)
507 (void) ThrowMagickException(exception,GetMagickModule(),
508 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
511 GetMagickPixelPacket(image,&pixel);
512 GetMagickPixelPacket(image,&target);
513 image_view=AcquireCacheView(image);
514 for (y=0; y < (long) image->rows; y++)
516 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
517 if (p == (const PixelPacket *) NULL)
519 indexes=GetCacheViewVirtualIndexQueue(image_view);
520 for (x=0; x < (long) image->columns; x++)
523 Start at the root and proceed level by level.
525 node_info=cube_info->root;
526 index=MaxTreeDepth-1;
527 for (level=1; level < MaxTreeDepth; level++)
529 SetMagickPixelPacket(image,p,indexes+x,&pixel);
530 id=ColorToNodeId(image,&pixel,index);
531 if (node_info->child[id] == (NodeInfo *) NULL)
533 node_info->child[id]=GetNodeInfo(cube_info,level);
534 if (node_info->child[id] == (NodeInfo *) NULL)
536 (void) ThrowMagickException(exception,GetMagickModule(),
537 ResourceLimitError,"MemoryAllocationFailed","`%s'",
542 node_info=node_info->child[id];
545 for (i=0; i < (long) node_info->number_unique; i++)
547 SetMagickPixelPacket(image,&node_info->list[i].pixel,
548 &node_info->list[i].index,&target);
549 if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
552 if (i < (long) node_info->number_unique)
553 node_info->list[i].count++;
556 if (node_info->number_unique == 0)
557 node_info->list=(ColorPacket *) AcquireMagickMemory(
558 sizeof(*node_info->list));
560 node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
561 (size_t) (i+1),sizeof(*node_info->list));
562 if (node_info->list == (ColorPacket *) NULL)
564 (void) ThrowMagickException(exception,GetMagickModule(),
565 ResourceLimitError,"MemoryAllocationFailed","`%s'",
569 node_info->list[i].pixel=(*p);
570 if ((image->colorspace == CMYKColorspace) ||
571 (image->storage_class == PseudoClass))
572 node_info->list[i].index=indexes[x];
573 node_info->list[i].count=1;
574 node_info->number_unique++;
579 proceed=SetImageProgress(image,EvaluateImageTag,y,image->rows);
580 if (proceed == MagickFalse)
583 image_view=DestroyCacheView(image_view);
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 + C o n c a t e n a t e C o l o r C o m p o n e n t %
596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 % ConcatenateColorComponent() returns the pixel as a canonical string.
600 % The format of the ConcatenateColorComponent() method is:
602 % void ConcatenateColorComponent(const MagickPixelPacket *pixel,
603 % const ChannelType channel,const ComplianceType compliance,char *tuple)
605 % A description of each parameter follows.
607 % o pixel: The pixel.
609 % channel: The channel.
611 % o compliance: Adhere to this color standard: SVG, X11, or XPM.
613 % tuple: The color tuple.
616 MagickExport void ConcatenateColorComponent(const MagickPixelPacket *pixel,
617 const ChannelType channel,const ComplianceType compliance,char *tuple)
620 component[MaxTextExtent];
645 color=QuantumRange-pixel->opacity;
656 if (compliance != SVGCompliance)
658 if (pixel->depth > 16)
660 (void) FormatMagickString(component,MaxTextExtent,"%10lu",
661 (unsigned long) ScaleQuantumToLong(RoundToQuantum(color)));
662 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
665 if (pixel->depth > 8)
667 (void) FormatMagickString(component,MaxTextExtent,"%5d",
668 ScaleQuantumToShort(RoundToQuantum(color)));
669 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
672 (void) FormatMagickString(component,MaxTextExtent,"%3d",
673 ScaleQuantumToChar(RoundToQuantum(color)));
674 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
677 if (channel == OpacityChannel)
679 (void) FormatMagickString(component,MaxTextExtent,"%g",
680 (double) (QuantumScale*color));
681 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
684 if ((channel == RedChannel) && (pixel->colorspace == HSLColorspace))
686 (void) FormatMagickString(component,MaxTextExtent,"%g",
687 360.0*(QuantumScale*color));
688 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
691 if (pixel->depth > 8)
693 (void) FormatMagickString(component,MaxTextExtent,"%g%%",
694 (double) (100.0*QuantumScale*color));
695 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
698 (void) FormatMagickString(component,MaxTextExtent,"%d",
699 ScaleQuantumToChar(RoundToQuantum(color)));
700 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 + D e f i n e I m a g e H i s t o g r a m %
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 % DefineImageHistogram() traverses the color cube tree and notes each colormap
715 % entry. A colormap entry is any node in the color cube tree where the
716 % of unique colors is not zero.
718 % The format of the DefineImageHistogram method is:
720 % DefineImageHistogram(const Image *image,NodeInfo *node_info,
721 % ColorPacket **unique_colors)
723 % A description of each parameter follows.
725 % o image: the image.
727 % o node_info: the address of a structure of type NodeInfo which points to a
728 % node in the color cube tree that is to be pruned.
730 % o histogram: the image histogram.
733 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
734 ColorPacket **histogram)
743 Traverse any children.
745 number_children=image->matte == MagickFalse ? 8UL : 16UL;
746 for (i=0; i < (long) number_children; i++)
747 if (node_info->child[i] != (NodeInfo *) NULL)
748 DefineImageHistogram(image,node_info->child[i],histogram);
749 if (node_info->level == (MaxTreeDepth-1))
755 for (i=0; i < (long) node_info->number_unique; i++)
757 (*histogram)->pixel=p->pixel;
758 (*histogram)->index=p->index;
759 (*histogram)->count=p->count;
767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 + D e s t r o y C o l o r L i s t %
775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
777 % DestroyColorList() deallocates memory associated with the color list.
779 % The format of the DestroyColorList method is:
781 % DestroyColorList(void)
785 static void *DestroyColorElement(void *color_info)
790 p=(ColorInfo *) color_info;
791 if (p->path != (char *) NULL)
792 p->path=DestroyString(p->path);
793 if (p->name != (char *) NULL)
794 p->name=DestroyString(p->name);
795 p=(ColorInfo *) RelinquishMagickMemory(p);
796 return((void *) NULL);
799 MagickExport void DestroyColorList(void)
801 AcquireSemaphoreInfo(&color_semaphore);
802 if (color_list != (LinkedListInfo *) NULL)
803 color_list=DestroyLinkedList(color_list,DestroyColorElement);
804 instantiate_color=MagickFalse;
805 RelinquishSemaphoreInfo(color_semaphore);
806 DestroySemaphoreInfo(&color_semaphore);
810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814 + D e s t r o y C u b e I n f o %
818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
820 % DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
822 % The format of the DestroyCubeInfo method is:
824 % DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
826 % A description of each parameter follows:
828 % o image: the image.
830 % o cube_info: the address of a structure of type CubeInfo.
833 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
839 Release color cube tree storage.
841 DestroyColorCube(image,cube_info->root);
844 nodes=cube_info->node_queue->next;
845 cube_info->node_queue=(Nodes *)
846 RelinquishMagickMemory(cube_info->node_queue);
847 cube_info->node_queue=nodes;
848 } while (cube_info->node_queue != (Nodes *) NULL);
849 return((CubeInfo *) RelinquishMagickMemory(cube_info));
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857 + D e s t r o y C o l o r C u b e %
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 % DestroyColorCube() traverses the color cube tree and frees the list of
866 % The format of the DestroyColorCube method is:
868 % void DestroyColorCube(const Image *image,const NodeInfo *node_info)
870 % A description of each parameter follows.
872 % o image: the image.
874 % o node_info: the address of a structure of type NodeInfo which points to a
875 % node in the color cube tree that is to be pruned.
878 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
887 Traverse any children.
889 number_children=image->matte == MagickFalse ? 8UL : 16UL;
890 for (i=0; i < (long) number_children; i++)
891 if (node_info->child[i] != (NodeInfo *) NULL)
892 DestroyColorCube(image,node_info->child[i]);
893 if (node_info->list != (ColorPacket *) NULL)
894 node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 + G e t C o l o r I n f o %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 % GetColorInfo() searches the color list for the specified name and if found
909 % returns attributes for that color.
911 % The format of the GetColorInfo method is:
913 % const PixelPacket *GetColorInfo(const char *name,
914 % ExceptionInfo *exception)
916 % A description of each parameter follows:
918 % o color_info: search the color list for the specified name and if found
919 % return attributes for that color.
921 % o name: the color name.
923 % o exception: return any errors or warnings in this structure.
926 MagickExport const ColorInfo *GetColorInfo(const char *name,
927 ExceptionInfo *exception)
930 colorname[MaxTextExtent];
932 register const ColorInfo
938 assert(exception != (ExceptionInfo *) NULL);
939 if ((color_list == (LinkedListInfo *) NULL) ||
940 (instantiate_color == MagickFalse))
941 if (InitializeColorList(exception) == MagickFalse)
942 return((const ColorInfo *) NULL);
943 if ((color_list == (LinkedListInfo *) NULL) ||
944 (IsLinkedListEmpty(color_list) != MagickFalse))
945 return((const ColorInfo *) NULL);
946 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
947 return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
949 Strip names of whitespace.
951 (void) CopyMagickString(colorname,name,MaxTextExtent);
952 for (q=colorname; *q != '\0'; q++)
954 if (isspace((int) ((unsigned char) *q)) == 0)
956 (void) CopyMagickString(q,q+1,MaxTextExtent);
960 Search for color tag.
962 AcquireSemaphoreInfo(&color_semaphore);
963 ResetLinkedListIterator(color_list);
964 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
965 while (p != (const ColorInfo *) NULL)
967 if (LocaleCompare(colorname,p->name) == 0)
969 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
971 if (p == (ColorInfo *) NULL)
972 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
973 "UnrecognizedColor","`%s'",name);
975 (void) InsertValueInLinkedList(color_list,0,
976 RemoveElementByValueFromLinkedList(color_list,p));
977 RelinquishSemaphoreInfo(color_semaphore);
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % G e t C o l o r I n f o L i s t %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % GetColorInfoList() returns any colors that match the specified pattern.
994 % The format of the GetColorInfoList function is:
996 % const ColorInfo **GetColorInfoList(const char *pattern,
997 % unsigned long *number_colors,ExceptionInfo *exception)
999 % A description of each parameter follows:
1001 % o pattern: Specifies a pointer to a text string containing a pattern.
1003 % o number_colors: This integer returns the number of colors in the list.
1005 % o exception: return any errors or warnings in this structure.
1009 #if defined(__cplusplus) || defined(c_plusplus)
1013 static int ColorInfoCompare(const void *x,const void *y)
1019 p=(const ColorInfo **) x,
1020 q=(const ColorInfo **) y;
1021 if (LocaleCompare((*p)->path,(*q)->path) == 0)
1022 return(LocaleCompare((*p)->name,(*q)->name));
1023 return(LocaleCompare((*p)->path,(*q)->path));
1026 #if defined(__cplusplus) || defined(c_plusplus)
1030 MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
1031 unsigned long *number_colors,ExceptionInfo *exception)
1036 register const ColorInfo
1043 Allocate color list.
1045 assert(pattern != (char *) NULL);
1046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1047 assert(number_colors != (unsigned long *) NULL);
1049 p=GetColorInfo("*",exception);
1050 if (p == (const ColorInfo *) NULL)
1051 return((const ColorInfo **) NULL);
1052 colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
1053 GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1054 if (colors == (const ColorInfo **) NULL)
1055 return((const ColorInfo **) NULL);
1057 Generate color list.
1059 AcquireSemaphoreInfo(&color_semaphore);
1060 ResetLinkedListIterator(color_list);
1061 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1062 for (i=0; p != (const ColorInfo *) NULL; )
1064 if ((p->stealth == MagickFalse) &&
1065 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1067 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1069 RelinquishSemaphoreInfo(color_semaphore);
1070 qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
1071 colors[i]=(ColorInfo *) NULL;
1072 *number_colors=(unsigned long) i;
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 % G e t C o l o r L i s t %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % GetColorList() returns any colors that match the specified pattern.
1089 % The format of the GetColorList function is:
1091 % char **GetColorList(const char *pattern,unsigned long *number_colors,
1092 % ExceptionInfo *exception)
1094 % A description of each parameter follows:
1096 % o pattern: Specifies a pointer to a text string containing a pattern.
1098 % o number_colors: This integer returns the number of colors in the list.
1100 % o exception: return any errors or warnings in this structure.
1104 #if defined(__cplusplus) || defined(c_plusplus)
1108 static int ColorCompare(const void *x,const void *y)
1114 p=(const char **) x;
1115 q=(const char **) y;
1116 return(LocaleCompare(*p,*q));
1119 #if defined(__cplusplus) || defined(c_plusplus)
1123 MagickExport char **GetColorList(const char *pattern,
1124 unsigned long *number_colors,ExceptionInfo *exception)
1129 register const ColorInfo
1136 Allocate color list.
1138 assert(pattern != (char *) NULL);
1139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1140 assert(number_colors != (unsigned long *) NULL);
1142 p=GetColorInfo("*",exception);
1143 if (p == (const ColorInfo *) NULL)
1144 return((char **) NULL);
1145 colors=(char **) AcquireQuantumMemory((size_t)
1146 GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1147 if (colors == (char **) NULL)
1148 return((char **) NULL);
1150 Generate color list.
1152 AcquireSemaphoreInfo(&color_semaphore);
1153 ResetLinkedListIterator(color_list);
1154 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1155 for (i=0; p != (const ColorInfo *) NULL; )
1157 if ((p->stealth == MagickFalse) &&
1158 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1159 colors[i++]=ConstantString(p->name);
1160 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1162 RelinquishSemaphoreInfo(color_semaphore);
1163 qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
1164 colors[i]=(char *) NULL;
1165 *number_colors=(unsigned long) i;
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174 + G e t C o l o r T u p l e %
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180 % GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
1181 % or hex string (e.g. #FF0000).
1183 % The format of the GetColorTuple method is:
1185 % GetColorTuple(const MagickPixelPacket *pixel,const MagickBooleanType hex,
1188 % A description of each parameter follows.
1190 % o pixel: the pixel.
1192 % o hex: A value other than zero returns the tuple in a hexidecimal format.
1194 % o tuple: Return the color tuple as this string.
1198 static void ConcatentateHexColorComponent(const MagickPixelPacket *pixel,
1199 const ChannelType channel,char *tuple)
1202 component[MaxTextExtent];
1225 case OpacityChannel:
1227 color=(MagickRealType) QuantumRange-pixel->opacity;
1238 if (pixel->depth > 32)
1240 (void) FormatMagickString(component,MaxTextExtent,"%08lX",
1241 ScaleQuantumToLong(RoundToQuantum(color)));
1242 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1245 if (pixel->depth > 16)
1247 (void) FormatMagickString(component,MaxTextExtent,"%08X",
1248 (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
1249 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1252 if (pixel->depth > 8)
1254 (void) FormatMagickString(component,MaxTextExtent,"%04X",
1255 ScaleQuantumToShort(RoundToQuantum(color)));
1256 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1259 (void) FormatMagickString(component,MaxTextExtent,"%02X",
1260 ScaleQuantumToChar(RoundToQuantum(color)));
1261 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1265 MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
1266 const MagickBooleanType hex,char *tuple)
1271 assert(pixel != (const MagickPixelPacket *) NULL);
1272 assert(tuple != (char *) NULL);
1273 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
1275 if (hex != MagickFalse)
1278 Convert pixel to hex color.
1280 (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
1281 ConcatentateHexColorComponent(pixel,RedChannel,tuple);
1282 ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
1283 ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
1284 if (pixel->colorspace == CMYKColorspace)
1285 ConcatentateHexColorComponent(pixel,IndexChannel,tuple);
1286 if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
1287 ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
1291 Convert pixel to rgb() or cmyk() color.
1294 if (color.depth > 8)
1296 #define SVGCompliant(component) ((MagickRealType) \
1297 ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(component))));
1303 SVG requires color depths > 8 expressed as percentages.
1305 status=color.red == SVGCompliant(color.red);
1306 status&=color.green == SVGCompliant(color.green);
1307 status&=color.blue == SVGCompliant(color.blue);
1308 if (color.colorspace != CMYKColorspace)
1309 status&=color.index == SVGCompliant(color.index);
1310 if (color.matte != MagickFalse)
1311 status&=color.opacity == SVGCompliant(color.opacity);
1312 if (status != MagickFalse)
1315 (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
1316 MagickColorspaceOptions,(long) color.colorspace),MaxTextExtent);
1317 if (color.matte != MagickFalse)
1318 (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
1319 (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
1320 ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
1321 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1322 ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
1323 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1324 ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
1325 if (color.colorspace == CMYKColorspace)
1327 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1328 ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple);
1330 if (color.matte != MagickFalse)
1332 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1333 ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
1335 (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 + G e t C u b e I n f o %
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 % GetCubeInfo() initializes the CubeInfo data structure.
1353 % The format of the GetCubeInfo method is:
1355 % cube_info=GetCubeInfo()
1357 % A description of each parameter follows.
1359 % o cube_info: A pointer to the Cube structure.
1362 static CubeInfo *GetCubeInfo(void)
1368 Initialize tree to describe color cube.
1370 cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
1371 if (cube_info == (CubeInfo *) NULL)
1372 return((CubeInfo *) NULL);
1373 (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
1375 Initialize root node.
1377 cube_info->root=GetNodeInfo(cube_info,0);
1378 if (cube_info->root == (NodeInfo *) NULL)
1379 return((CubeInfo *) NULL);
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 % G e t I m a g e H i s t o g r a m %
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 % GetImageHistogram() returns the unique colors in an image.
1396 % The format of the GetImageHistogram method is:
1398 % unsigned long GetImageHistogram(const Image *image,
1399 % unsigned long *number_colors,ExceptionInfo *exception)
1401 % A description of each parameter follows.
1403 % o image: the image.
1405 % o file: Write a histogram of the color distribution to this file handle.
1407 % o exception: return any errors or warnings in this structure.
1410 MagickExport ColorPacket *GetImageHistogram(const Image *image,
1411 unsigned long *number_colors,ExceptionInfo *exception)
1420 histogram=(ColorPacket *) NULL;
1421 cube_info=ClassifyImageColors(image,exception);
1422 if (cube_info != (CubeInfo *) NULL)
1424 histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
1425 sizeof(*histogram));
1426 if (histogram == (ColorPacket *) NULL)
1427 (void) ThrowMagickException(exception,GetMagickModule(),
1428 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1434 *number_colors=cube_info->colors;
1436 DefineImageHistogram(image,cube_info->root,&root);
1439 cube_info=DestroyCubeInfo(image,cube_info);
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 + G e t N o d e I n f o %
1452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454 % GetNodeInfo() allocates memory for a new node in the color cube tree and
1455 % presets all fields to zero.
1457 % The format of the GetNodeInfo method is:
1459 % NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1461 % A description of each parameter follows.
1463 % o cube_info: A pointer to the CubeInfo structure.
1465 % o level: Specifies the level in the storage_class the node resides.
1468 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1473 if (cube_info->free_nodes == 0)
1479 Allocate a new nodes of nodes.
1481 nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
1482 if (nodes == (Nodes *) NULL)
1483 return((NodeInfo *) NULL);
1484 nodes->next=cube_info->node_queue;
1485 cube_info->node_queue=nodes;
1486 cube_info->node_info=nodes->nodes;
1487 cube_info->free_nodes=NodesInAList;
1489 cube_info->free_nodes--;
1490 node_info=cube_info->node_info++;
1491 (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
1492 node_info->level=level;
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501 % G e t N u m b e r C o l o r s %
1505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507 % GetNumberColors() returns the number of unique colors in an image.
1509 % The format of the GetNumberColors method is:
1511 % unsigned long GetNumberColors(const Image *image,FILE *file,
1512 % ExceptionInfo *exception)
1514 % A description of each parameter follows.
1516 % o image: the image.
1518 % o file: Write a histogram of the color distribution to this file handle.
1520 % o exception: return any errors or warnings in this structure.
1524 #if defined(__cplusplus) || defined(c_plusplus)
1528 static int HistogramCompare(const void *x,const void *y)
1534 color_1=(const ColorPacket *) x;
1535 color_2=(const ColorPacket *) y;
1536 if (color_2->pixel.red != color_1->pixel.red)
1537 return((int) color_1->pixel.red-(int) color_2->pixel.red);
1538 if (color_2->pixel.green != color_1->pixel.green)
1539 return((int) color_1->pixel.green-(int) color_2->pixel.green);
1540 if (color_2->pixel.blue != color_1->pixel.blue)
1541 return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
1542 return((int) color_2->count-(int) color_1->count);
1545 #if defined(__cplusplus) || defined(c_plusplus)
1549 MagickExport unsigned long GetNumberColors(const Image *image,FILE *file,
1550 ExceptionInfo *exception)
1552 #define HistogramImageTag "Histogram/Image"
1555 color[MaxTextExtent],
1557 tuple[MaxTextExtent];
1565 register ColorPacket
1575 if (file == (FILE *) NULL)
1580 cube_info=ClassifyImageColors(image,exception);
1581 if (cube_info != (CubeInfo *) NULL)
1582 number_colors=cube_info->colors;
1583 cube_info=DestroyCubeInfo(image,cube_info);
1584 return(number_colors);
1586 histogram=GetImageHistogram(image,&number_colors,exception);
1587 if (histogram == (ColorPacket *) NULL)
1588 return(number_colors);
1589 qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1591 GetMagickPixelPacket(image,&pixel);
1593 for (i=0; i < (long) number_colors; i++)
1595 SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel);
1596 (void) CopyMagickString(tuple,"(",MaxTextExtent);
1597 ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1598 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1599 ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1600 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1601 ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1602 if (pixel.colorspace == CMYKColorspace)
1604 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1605 ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
1607 if (pixel.matte != MagickFalse)
1609 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1610 ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
1612 (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1613 (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
1614 GetColorTuple(&pixel,MagickTrue,hex);
1615 (void) fprintf(file,MagickSizeFormat,p->count);
1616 (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
1617 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1618 (QuantumTick(i,number_colors) != MagickFalse))
1619 (void) image->progress_monitor(HistogramImageTag,i,number_colors,
1620 image->client_data);
1623 (void) fflush(file);
1624 histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
1625 return(number_colors);
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 + I n i t i a l i z e C o l o r L i s t %
1637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 % InitializeColorList() initializes the color list.
1641 % The format of the InitializeColorList method is:
1643 % MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1645 % A description of each parameter follows.
1647 % o exception: return any errors or warnings in this structure.
1650 static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1652 if ((color_list == (LinkedListInfo *) NULL) &&
1653 (instantiate_color == MagickFalse))
1655 AcquireSemaphoreInfo(&color_semaphore);
1656 if ((color_list == (LinkedListInfo *) NULL) &&
1657 (instantiate_color == MagickFalse))
1659 (void) LoadColorLists(ColorFilename,exception);
1660 instantiate_color=MagickTrue;
1662 RelinquishSemaphoreInfo(color_semaphore);
1664 return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 + I s C o l o r S i m i l a r %
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678 % IsColorSimilar() returns MagickTrue if the distance between two colors is
1679 % less than the specified distance in a linear three dimensional color space.
1680 % This method is used by ColorFloodFill() and other algorithms which
1681 % compare two colors.
1683 % The format of the IsColorSimilar method is:
1685 % void IsColorSimilar(const Image *image,const PixelPacket *p,
1686 % const PixelPacket *q)
1688 % A description of each parameter follows:
1690 % o image: the image.
1698 static inline double MagickMax(const double x,const double y)
1705 MagickExport MagickBooleanType IsColorSimilar(const Image *image,
1706 const PixelPacket *p,const PixelPacket *q)
1712 register MagickRealType
1717 if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
1718 return(IsColorEqual(p,q));
1719 fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
1723 if (image->matte != MagickFalse)
1725 alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1726 beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1728 pixel=alpha*p->red-beta*q->red;
1729 distance=pixel*pixel;
1730 if (distance > fuzz)
1731 return(MagickFalse);
1732 pixel=alpha*p->green-beta*q->green;
1733 distance+=pixel*pixel;
1734 if (distance > fuzz)
1735 return(MagickFalse);
1736 pixel=alpha*p->blue-beta*q->blue;
1737 distance+=pixel*pixel;
1738 if (distance > fuzz)
1739 return(MagickFalse);
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 % I s G r a y I m a g e %
1752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 % IsGrayImage() returns MagickTrue if all the pixels in the image have the
1755 % same red, green, and blue intensities.
1757 % The format of the IsGrayImage method is:
1759 % MagickBooleanType IsGrayImage(const Image *image,
1760 % ExceptionInfo *exception)
1762 % A description of each parameter follows:
1764 % o image: the image.
1766 % o exception: return any errors or warnings in this structure.
1769 MagickExport MagickBooleanType IsGrayImage(const Image *image,
1770 ExceptionInfo *exception)
1775 register const PixelPacket
1778 assert(image != (Image *) NULL);
1779 assert(image->signature == MagickSignature);
1780 if (image->debug != MagickFalse)
1781 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1782 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1783 (image->type == GrayscaleMatteType))
1785 if (image->colorspace == CMYKColorspace)
1786 return(MagickFalse);
1788 switch (image->storage_class)
1791 case UndefinedClass:
1802 image_view=AcquireCacheView(image);
1803 for (y=0; y < (long) image->rows; y++)
1805 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1806 if (p == (const PixelPacket *) NULL)
1808 for (x=0; x < (long) image->columns; x++)
1810 if (IsGrayPixel(p) == MagickFalse)
1815 if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1819 if (type == UndefinedType)
1822 image_view=DestroyCacheView(image_view);
1831 for (i=0; i < (long) image->colors; i++)
1833 if (IsGrayPixel(p) == MagickFalse)
1838 if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1845 if (type == UndefinedType)
1846 return(MagickFalse);
1847 ((Image *) image)->type=type;
1848 if ((type == GrayscaleType) && (image->matte != MagickFalse))
1849 ((Image *) image)->type=GrayscaleMatteType;
1854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858 % I s H i s t o g r a m I m a g e %
1862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864 % IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
1867 % The format of the IsHistogramImage method is:
1869 % MagickBooleanType IsHistogramImage(const Image *image,
1870 % ExceptionInfo *exception)
1872 % A description of each parameter follows.
1874 % o image: the image.
1876 % o exception: return any errors or warnings in this structure.
1879 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
1880 ExceptionInfo *exception)
1882 #define MaximumUniqueColors 1024
1894 register const IndexPacket
1897 register const PixelPacket
1917 assert(image != (Image *) NULL);
1918 assert(image->signature == MagickSignature);
1919 if (image->debug != MagickFalse)
1920 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1921 if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1923 if (image->storage_class == PseudoClass)
1924 return(MagickFalse);
1926 Initialize color description tree.
1928 cube_info=GetCubeInfo();
1929 if (cube_info == (CubeInfo *) NULL)
1931 (void) ThrowMagickException(exception,GetMagickModule(),
1932 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1933 return(MagickFalse);
1935 GetMagickPixelPacket(image,&pixel);
1936 GetMagickPixelPacket(image,&target);
1937 image_view=AcquireCacheView(image);
1938 for (y=0; y < (long) image->rows; y++)
1940 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1941 if (p == (const PixelPacket *) NULL)
1943 indexes=GetCacheViewVirtualIndexQueue(image_view);
1944 for (x=0; x < (long) image->columns; x++)
1947 Start at the root and proceed level by level.
1949 node_info=cube_info->root;
1950 index=MaxTreeDepth-1;
1951 for (level=1; level < MaxTreeDepth; level++)
1953 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1954 id=ColorToNodeId(image,&pixel,index);
1955 if (node_info->child[id] == (NodeInfo *) NULL)
1957 node_info->child[id]=GetNodeInfo(cube_info,level);
1958 if (node_info->child[id] == (NodeInfo *) NULL)
1960 (void) ThrowMagickException(exception,GetMagickModule(),
1961 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1966 node_info=node_info->child[id];
1969 if (level < MaxTreeDepth)
1971 for (i=0; i < (long) node_info->number_unique; i++)
1973 SetMagickPixelPacket(image,&node_info->list[i].pixel,
1974 &node_info->list[i].index,&target);
1975 if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
1978 if (i < (long) node_info->number_unique)
1979 node_info->list[i].count++;
1983 Add this unique color to the color list.
1985 if (node_info->number_unique == 0)
1986 node_info->list=(ColorPacket *) AcquireMagickMemory(
1987 sizeof(*node_info->list));
1989 node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
1990 (size_t) (i+1),sizeof(*node_info->list));
1991 if (node_info->list == (ColorPacket *) NULL)
1993 (void) ThrowMagickException(exception,GetMagickModule(),
1994 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1998 node_info->list[i].pixel=(*p);
1999 if ((image->colorspace == CMYKColorspace) ||
2000 (image->storage_class == PseudoClass))
2001 node_info->list[i].index=indexes[x];
2002 node_info->list[i].count=1;
2003 node_info->number_unique++;
2004 cube_info->colors++;
2005 if (cube_info->colors > MaximumUniqueColors)
2010 if (x < (long) image->columns)
2013 image_view=DestroyCacheView(image_view);
2014 cube_info=DestroyCubeInfo(image,cube_info);
2015 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023 + I s I m a g e S i m i l a r %
2027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029 % IsImageSimilar() returns true if the target is similar to a region of the
2032 % The format of the IsImageSimilar method is:
2034 % MagickBooleanType IsImageSimilar(const Image *image,
2035 % const Image *target_image,long *x_offset,long *y_offset,
2036 % ExceptionInfo *exception)
2038 % A description of each parameter follows:
2040 % o image: the image.
2042 % o target_image: the target image.
2044 % o x_offset: On input the starting x position to search for a match;
2045 % on output the x position of the first match found.
2047 % o y_offset: On input the starting y position to search for a match;
2048 % on output the y position of the first match found.
2050 % o exception: return any errors or warnings in this structure.
2053 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
2054 const Image *target_image,long *x_offset,long *y_offset,
2055 ExceptionInfo *exception)
2057 #define SearchImageText " Searching image... "
2070 register const PixelPacket
2074 register const IndexPacket
2086 assert(image != (Image *) NULL);
2087 assert(image->signature == MagickSignature);
2088 if (image->debug != MagickFalse)
2089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2090 assert(target_image != (Image *) NULL);
2091 assert(target_image->signature == MagickSignature);
2092 assert(x_offset != (long *) NULL);
2093 assert(y_offset != (long *) NULL);
2094 assert(exception != (ExceptionInfo *) NULL);
2096 GetMagickPixelPacket(image,&pixel);
2097 GetMagickPixelPacket(image,&target);
2098 image_view=AcquireCacheView(image);
2099 target_view=AcquireCacheView(target_image);
2100 for (y=(*y_offset); y < (long) image->rows; y++)
2102 for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
2104 for (j=0; j < (long) target_image->rows; j++)
2106 for (i=0; i < (long) target_image->columns; i++)
2108 p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
2109 indexes=GetCacheViewVirtualIndexQueue(image_view);
2110 SetMagickPixelPacket(image,p,indexes,&pixel);
2111 q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
2112 target_indexes=GetCacheViewVirtualIndexQueue(target_view);
2113 SetMagickPixelPacket(image,q,target_indexes,&target);
2114 if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
2117 if (i < (long) target_image->columns)
2120 if (j == (long) target_image->rows)
2123 if (x < (long) image->columns)
2125 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
2126 (QuantumTick(y,image->rows) != MagickFalse))
2128 status=image->progress_monitor(SearchImageText,y,image->rows,
2129 image->client_data);
2130 if (status == MagickFalse)
2134 target_view=DestroyCacheView(target_view);
2135 image_view=DestroyCacheView(image_view);
2138 return(y < (long) image->rows ? MagickTrue : MagickFalse);
2142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2146 + I s M a g i c k C o l o r S i m i l a r %
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2152 % IsMagickColorSimilar() returns true if the distance between two colors is
2153 % less than the specified distance in a linear three dimensional color space.
2154 % This method is used by ColorFloodFill() and other algorithms which
2155 % compare two colors.
2157 % The format of the IsMagickColorSimilar method is:
2159 % MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2160 % const MagickPixelPacket *q)
2162 % A description of each parameter follows:
2169 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2170 const MagickPixelPacket *q)
2176 register MagickRealType
2181 if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
2182 return(IsMagickColorEqual(p,q));
2184 fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2187 fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
2189 fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2191 if (p->matte != MagickFalse)
2192 alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
2194 if (q->matte != MagickFalse)
2195 beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
2196 if (p->colorspace == CMYKColorspace)
2198 alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
2199 beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
2201 pixel=alpha*p->red-beta*q->red;
2202 if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
2203 (p->colorspace == HWBColorspace))
2205 if (fabs(p->red-q->red) > (QuantumRange/2))
2207 if (p->red > (QuantumRange/2))
2208 pixel=alpha*(p->red-QuantumRange)-beta*q->red;
2210 pixel=alpha*p->red-beta*(q->red-QuantumRange);
2214 distance=pixel*pixel;
2215 if (distance > fuzz)
2216 return(MagickFalse);
2217 pixel=alpha*p->green-beta*q->green;
2218 distance+=pixel*pixel;
2219 if (distance > fuzz)
2220 return(MagickFalse);
2221 pixel=alpha*p->blue-beta*q->blue;
2222 distance+=pixel*pixel;
2223 if (distance > fuzz)
2224 return(MagickFalse);
2225 pixel=p->opacity-q->opacity;
2226 distance+=pixel*pixel;
2227 if (distance > fuzz)
2228 return(MagickFalse);
2233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 % I s M o n o c h r o m e I m a g e %
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % IsMonochromeImage() returns MagickTrue if all the pixels in the image have
2244 % the same red, green, and blue intensities and the intensity is either
2245 % 0 or QuantumRange.
2247 % The format of the IsMonochromeImage method is:
2249 % MagickBooleanType IsMonochromeImage(const Image *image,
2250 % ExceptionInfo *exception)
2252 % A description of each parameter follows:
2254 % o image: the image.
2256 % o exception: return any errors or warnings in this structure.
2259 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
2260 ExceptionInfo *exception)
2265 register const PixelPacket
2268 assert(image != (Image *) NULL);
2269 assert(image->signature == MagickSignature);
2270 if (image->debug != MagickFalse)
2271 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2272 if (image->type == BilevelType)
2274 if (image->colorspace == CMYKColorspace)
2275 return(MagickFalse);
2277 switch (image->storage_class)
2280 case UndefinedClass:
2291 image_view=AcquireCacheView(image);
2292 for (y=0; y < (long) image->rows; y++)
2294 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2295 if (p == (const PixelPacket *) NULL)
2297 for (x=0; x < (long) image->columns; x++)
2299 if (IsMonochromePixel(p) == MagickFalse)
2306 if (type == UndefinedType)
2309 image_view=DestroyCacheView(image_view);
2310 if (y == (long) image->rows)
2311 ((Image *) image)->type=BilevelType;
2320 for (i=0; i < (long) image->colors; i++)
2322 if (IsMonochromePixel(p) == MagickFalse)
2332 if (type == UndefinedType)
2333 return(MagickFalse);
2334 ((Image *) image)->type=type;
2339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 + I s O p a c i t y S i m i l a r %
2347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2349 % IsOpacitySimilar() returns true if the distance between two opacity
2350 % values is less than the specified distance in a linear color space. This
2351 % method is used by MatteFloodFill() and other algorithms which compare
2352 % two opacity values.
2354 % The format of the IsOpacitySimilar method is:
2356 % void IsOpacitySimilar(const Image *image,const PixelPacket *p,
2357 % const PixelPacket *q)
2359 % A description of each parameter follows:
2361 % o image: the image.
2368 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
2369 const PixelPacket *p,const PixelPacket *q)
2375 register MagickRealType
2378 if (image->matte == MagickFalse)
2380 if (p->opacity == q->opacity)
2382 fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
2383 pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
2384 distance=pixel*pixel;
2385 if (distance > fuzz)
2386 return(MagickFalse);
2391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395 % I s O p a q u e I m a g e %
2399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2401 % IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
2402 % an opacity value other than opaque (0).
2404 % The format of the IsOpaqueImage method is:
2406 % MagickBooleanType IsOpaqueImage(const Image *image,
2407 % ExceptionInfo *exception)
2409 % A description of each parameter follows:
2411 % o image: the image.
2413 % o exception: return any errors or warnings in this structure.
2416 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
2417 ExceptionInfo *exception)
2422 register const PixelPacket
2432 Determine if image is opaque.
2434 assert(image != (Image *) NULL);
2435 assert(image->signature == MagickSignature);
2436 if (image->debug != MagickFalse)
2437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2438 if (image->matte == MagickFalse)
2440 image_view=AcquireCacheView(image);
2441 for (y=0; y < (long) image->rows; y++)
2443 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2444 if (p == (const PixelPacket *) NULL)
2446 for (x=0; x < (long) image->columns; x++)
2448 if (p->opacity != OpaqueOpacity)
2452 if (x < (long) image->columns)
2455 image_view=DestroyCacheView(image_view);
2456 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464 % I s P a l e t t e I m a g e %
2468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470 % IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
2471 % unique colors or less.
2473 % The format of the IsPaletteImage method is:
2475 % MagickBooleanType IsPaletteImage(const Image *image,
2476 % ExceptionInfo *exception)
2478 % A description of each parameter follows.
2480 % o image: the image.
2482 % o exception: return any errors or warnings in this structure.
2485 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
2486 ExceptionInfo *exception)
2498 register const IndexPacket
2501 register const PixelPacket
2521 assert(image != (Image *) NULL);
2522 assert(image->signature == MagickSignature);
2523 if (image->debug != MagickFalse)
2524 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2525 if ((image->storage_class == PseudoClass) && (image->colors <= 256))
2527 if (image->storage_class == PseudoClass)
2528 return(MagickFalse);
2530 Initialize color description tree.
2532 cube_info=GetCubeInfo();
2533 if (cube_info == (CubeInfo *) NULL)
2535 (void) ThrowMagickException(exception,GetMagickModule(),
2536 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2537 return(MagickFalse);
2539 GetMagickPixelPacket(image,&pixel);
2540 GetMagickPixelPacket(image,&target);
2541 image_view=AcquireCacheView(image);
2542 for (y=0; y < (long) image->rows; y++)
2544 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2545 if (p == (const PixelPacket *) NULL)
2547 indexes=GetCacheViewVirtualIndexQueue(image_view);
2548 for (x=0; x < (long) image->columns; x++)
2551 Start at the root and proceed level by level.
2553 node_info=cube_info->root;
2554 index=MaxTreeDepth-1;
2555 for (level=1; level < MaxTreeDepth; level++)
2557 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2558 id=ColorToNodeId(image,&pixel,index);
2559 if (node_info->child[id] == (NodeInfo *) NULL)
2561 node_info->child[id]=GetNodeInfo(cube_info,level);
2562 if (node_info->child[id] == (NodeInfo *) NULL)
2564 (void) ThrowMagickException(exception,GetMagickModule(),
2565 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2570 node_info=node_info->child[id];
2573 if (level < MaxTreeDepth)
2575 for (i=0; i < (long) node_info->number_unique; i++)
2577 SetMagickPixelPacket(image,&node_info->list[i].pixel,
2578 &node_info->list[i].index,&target);
2579 if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
2582 if (i < (long) node_info->number_unique)
2583 node_info->list[i].count++;
2587 Add this unique color to the color list.
2589 if (node_info->number_unique == 0)
2590 node_info->list=(ColorPacket *) AcquireMagickMemory(
2591 sizeof(*node_info->list));
2593 node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
2594 (size_t) (i+1),sizeof(*node_info->list));
2595 if (node_info->list == (ColorPacket *) NULL)
2597 (void) ThrowMagickException(exception,GetMagickModule(),
2598 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2602 node_info->list[i].pixel=(*p);
2603 if ((image->colorspace == CMYKColorspace) ||
2604 (image->storage_class == PseudoClass))
2605 node_info->list[i].index=indexes[x];
2606 node_info->list[i].count=1;
2607 node_info->number_unique++;
2608 cube_info->colors++;
2609 if (cube_info->colors > 256)
2614 if (x < (long) image->columns)
2617 image_view=DestroyCacheView(image_view);
2618 cube_info=DestroyCubeInfo(image,cube_info);
2619 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627 % L i s t C o l o r I n f o %
2631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633 % ListColorInfo() lists color names to the specified file. Color names
2634 % are a convenience. Rather than defining a color by its red, green, and
2635 % blue intensities just use a color name such as white, blue, or yellow.
2637 % The format of the ListColorInfo method is:
2639 % MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
2641 % A description of each parameter follows.
2643 % o file: List color names to this file handle.
2645 % o exception: return any errors or warnings in this structure.
2648 MagickExport MagickBooleanType ListColorInfo(FILE *file,
2649 ExceptionInfo *exception)
2652 tuple[MaxTextExtent];
2667 List name and attributes of each color in the list.
2669 if (file == (const FILE *) NULL)
2671 color_info=GetColorInfoList("*",&number_colors,exception);
2672 if (color_info == (const ColorInfo **) NULL)
2673 return(MagickFalse);
2674 path=(const char *) NULL;
2675 for (i=0; i < (long) number_colors; i++)
2677 if (color_info[i]->stealth != MagickFalse)
2679 if ((path == (const char *) NULL) ||
2680 (LocaleCompare(path,color_info[i]->path) != 0))
2682 if (color_info[i]->path != (char *) NULL)
2683 (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
2684 (void) fprintf(file,"Name Color "
2686 (void) fprintf(file,"-------------------------------------------------"
2687 "------------------------------\n");
2689 path=color_info[i]->path;
2690 (void) fprintf(file,"%-21.21s ",color_info[i]->name);
2691 GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
2692 (void) fprintf(file,"%-45.45s ",tuple);
2693 if ((color_info[i]->compliance & SVGCompliance) != 0)
2694 (void) fprintf(file,"SVG ");
2695 if ((color_info[i]->compliance & X11Compliance) != 0)
2696 (void) fprintf(file,"X11 ");
2697 if ((color_info[i]->compliance & XPMCompliance) != 0)
2698 (void) fprintf(file,"XPM ");
2699 (void) fprintf(file,"\n");
2701 color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
2702 (void) fflush(file);
2707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711 + L o a d C o l o r L i s t %
2715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2717 % LoadColorList() loads the color configuration file which provides a mapping
2718 % between color attributes and a color name.
2720 % The format of the LoadColorList method is:
2722 % MagickBooleanType LoadColorList(const char *xml,const char *filename,
2723 % const unsigned long depth,ExceptionInfo *exception)
2725 % A description of each parameter follows:
2727 % o xml: The color list in XML format.
2729 % o filename: The color list filename.
2731 % o depth: depth of <include /> statements.
2733 % o exception: return any errors or warnings in this structure.
2736 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
2737 const unsigned long depth,ExceptionInfo *exception)
2740 keyword[MaxTextExtent],
2753 Load the color map file.
2755 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2756 "Loading color file \"%s\" ...",filename);
2757 if (xml == (char *) NULL)
2758 return(MagickFalse);
2759 if (color_list == (LinkedListInfo *) NULL)
2761 color_list=NewLinkedList(0);
2762 if (color_list == (LinkedListInfo *) NULL)
2764 ThrowFileException(exception,ResourceLimitError,
2765 "MemoryAllocationFailed",filename);
2766 return(MagickFalse);
2770 color_info=(ColorInfo *) NULL;
2771 token=AcquireString(xml);
2772 for (q=(char *) xml; *q != '\0'; )
2777 GetMagickToken(q,&q,token);
2780 (void) CopyMagickString(keyword,token,MaxTextExtent);
2781 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2786 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2787 GetMagickToken(q,&q,token);
2790 if (LocaleNCompare(keyword,"<!--",4) == 0)
2795 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2796 GetMagickToken(q,&q,token);
2799 if (LocaleCompare(keyword,"<include") == 0)
2804 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2806 (void) CopyMagickString(keyword,token,MaxTextExtent);
2807 GetMagickToken(q,&q,token);
2810 GetMagickToken(q,&q,token);
2811 if (LocaleCompare(keyword,"file") == 0)
2814 (void) ThrowMagickException(exception,GetMagickModule(),
2815 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2819 path[MaxTextExtent],
2822 GetPathComponent(filename,HeadPath,path);
2824 (void) ConcatenateMagickString(path,DirectorySeparator,
2826 if (*token == *DirectorySeparator)
2827 (void) CopyMagickString(path,token,MaxTextExtent);
2829 (void) ConcatenateMagickString(path,token,MaxTextExtent);
2830 xml=FileToString(path,~0,exception);
2831 if (xml != (char *) NULL)
2833 status=LoadColorList(xml,path,depth+1,exception);
2834 xml=(char *) RelinquishMagickMemory(xml);
2841 if (LocaleCompare(keyword,"<color") == 0)
2846 color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
2847 if (color_info == (ColorInfo *) NULL)
2848 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2849 (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
2850 color_info->path=ConstantString(filename);
2851 color_info->signature=MagickSignature;
2854 if (color_info == (ColorInfo *) NULL)
2856 if (LocaleCompare(keyword,"/>") == 0)
2858 status=AppendValueToLinkedList(color_list,color_info);
2859 if (status == MagickFalse)
2860 (void) ThrowMagickException(exception,GetMagickModule(),
2861 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2863 color_info=(ColorInfo *) NULL;
2865 GetMagickToken(q,(const char **) NULL,token);
2868 GetMagickToken(q,&q,token);
2869 GetMagickToken(q,&q,token);
2875 if (LocaleCompare((char *) keyword,"color") == 0)
2877 (void) QueryMagickColor(token,&color_info->color,exception);
2880 if (LocaleCompare((char *) keyword,"compliance") == 0)
2885 compliance=color_info->compliance;
2886 if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
2887 compliance|=SVGCompliance;
2888 if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
2889 compliance|=X11Compliance;
2890 if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
2891 compliance|=XPMCompliance;
2892 color_info->compliance=(ComplianceType) compliance;
2900 if (LocaleCompare((char *) keyword,"name") == 0)
2902 color_info->name=ConstantString(token);
2910 if (LocaleCompare((char *) keyword,"stealth") == 0)
2912 color_info->stealth=IsMagickTrue(token);
2921 token=(char *) RelinquishMagickMemory(token);
2926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930 % L o a d C o l o r L i s t s %
2934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2936 % LoadColorList() loads one or more color configuration file which provides a
2937 % mapping between color attributes and a color name.
2939 % The format of the LoadColorLists method is:
2941 % MagickBooleanType LoadColorLists(const char *filename,
2942 % ExceptionInfo *exception)
2944 % A description of each parameter follows:
2946 % o filename: the font file name.
2948 % o exception: return any errors or warnings in this structure.
2951 static MagickBooleanType LoadColorLists(const char *filename,
2952 ExceptionInfo *exception)
2954 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
2955 return(LoadColorList(ColorMap,"built-in",0,exception));
2967 options=GetConfigureOptions(filename,exception);
2968 option=(const StringInfo *) GetNextValueInLinkedList(options);
2969 while (option != (const StringInfo *) NULL)
2971 status|=LoadColorList((const char *) GetStringInfoDatum(option),
2972 GetStringInfoPath(option),0,exception);
2973 option=(const StringInfo *) GetNextValueInLinkedList(options);
2975 options=DestroyConfigureOptions(options);
2976 if ((color_list == (LinkedListInfo *) NULL) ||
2977 (IsLinkedListEmpty(color_list) != MagickFalse))
2978 status|=LoadColorList(ColorMap,"built-in",0,exception);
2979 return(status != 0 ? MagickTrue : MagickFalse);
2984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 % Q u e r y C o l o r D a t a b a s e %
2992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994 % QueryColorDatabase() returns the red, green, blue, and opacity intensities
2995 % for a given color name.
2997 % The format of the QueryColorDatabase method is:
2999 % MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
3000 % ExceptionInfo *exception)
3002 % A description of each parameter follows:
3004 % o name: the color name (e.g. white, blue, yellow).
3006 % o color: the red, green, blue, and opacity intensities values of the
3007 % named color in this structure.
3009 % o exception: return any errors or warnings in this structure.
3013 static inline double MagickMin(const double x,const double y)
3020 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
3021 PixelPacket *color,ExceptionInfo *exception)
3029 status=QueryMagickColor(name,&pixel,exception);
3030 color->opacity=RoundToQuantum(pixel.opacity);
3031 if (pixel.colorspace == CMYKColorspace)
3033 color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3034 QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
3035 pixel.index)+pixel.index))));
3036 color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3037 QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
3038 pixel.index)+pixel.index))));
3039 color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3040 QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
3041 pixel.index)+pixel.index))));
3044 color->red=RoundToQuantum(pixel.red);
3045 color->green=RoundToQuantum(pixel.green);
3046 color->blue=RoundToQuantum(pixel.blue);
3051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 % Q u e r y C o l o r n a m e %
3059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3061 % QueryColorname() returns a named color for the given color intensity. If
3062 % an exact match is not found, a rgb() color is returned instead.
3064 % The format of the QueryColorname method is:
3066 % MagickBooleanType QueryColorname(const Image *image,
3067 % const PixelPacket *color,const ComplianceType compliance,char *name,
3068 % ExceptionInfo *exception)
3070 % A description of each parameter follows.
3072 % o image: the image.
3074 % o color: the color intensities.
3076 % o compliance: Adhere to this color standard: SVG, X11, or XPM.
3078 % o name: Return the color name or hex value.
3080 % o exception: return any errors or warnings in this structure.
3083 MagickExport MagickBooleanType QueryColorname(const Image *image,
3084 const PixelPacket *color,const ComplianceType compliance,char *name,
3085 ExceptionInfo *exception)
3090 GetMagickPixelPacket(image,&pixel);
3091 SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
3092 return(QueryMagickColorname(image,&pixel,compliance,name,exception));
3096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100 % Q u e r y M a g i c k C o l o r %
3104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3106 % QueryMagickColor() returns the red, green, blue, and opacity intensities
3107 % for a given color name.
3109 % The format of the QueryMagickColor method is:
3111 % MagickBooleanType QueryMagickColor(const char *name,
3112 % MagickPixelPacket *color,ExceptionInfo *exception)
3114 % A description of each parameter follows:
3116 % o name: the color name (e.g. white, blue, yellow).
3118 % o color: the red, green, blue, and opacity intensities values of the
3119 % named color in this structure.
3121 % o exception: return any errors or warnings in this structure.
3124 MagickExport MagickBooleanType QueryMagickColor(const char *name,
3125 MagickPixelPacket *color,ExceptionInfo *exception)
3139 register const ColorInfo
3146 Initialize color return value.
3148 assert(name != (const char *) NULL);
3149 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
3150 assert(color != (MagickPixelPacket *) NULL);
3151 GetMagickPixelPacket((Image *) NULL,color);
3152 if ((name == (char *) NULL) || (*name == '\0'))
3153 name=BackgroundColor;
3154 while (isspace((int) ((unsigned char) *name)) != 0)
3174 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
3176 for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
3181 pixel.red=pixel.green;
3182 pixel.green=pixel.blue;
3184 for (i=(long) (n/3-1); i >= 0; i--)
3188 if ((c >= '0') && (c <= '9'))
3189 pixel.blue|=(int) (c-'0');
3191 if ((c >= 'A') && (c <= 'F'))
3192 pixel.blue|=(int) c-((int) 'A'-10);
3194 if ((c >= 'a') && (c <= 'f'))
3195 pixel.blue|=(int) c-((int) 'a'-10);
3197 return(MagickFalse);
3199 } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3206 (void) ThrowMagickException(exception,GetMagickModule(),
3207 OptionWarning,"UnrecognizedColor","`%s'",name);
3208 return(MagickFalse);
3212 pixel.red=pixel.green;
3213 pixel.green=pixel.blue;
3214 pixel.blue=pixel.opacity;
3216 for (i=(long) (n/4-1); i >= 0; i--)
3220 if ((c >= '0') && (c <= '9'))
3221 pixel.opacity|=(int) (c-'0');
3223 if ((c >= 'A') && (c <= 'F'))
3224 pixel.opacity|=(int) c-((int) 'A'-10);
3226 if ((c >= 'a') && (c <= 'f'))
3227 pixel.opacity|=(int) c-((int) 'a'-10);
3229 return(MagickFalse);
3231 } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3234 color->colorspace=RGBColorspace;
3235 color->matte=MagickFalse;
3236 range=GetQuantumRange(depth);
3237 color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
3238 color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
3239 color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
3240 color->opacity=(MagickRealType) OpaqueOpacity;
3243 color->matte=MagickTrue;
3244 color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
3245 pixel.opacity,range));
3250 if (strchr(name,'(') != (char *) NULL)
3253 colorspace[MaxTextExtent];
3256 Parse color of the form rgb(100,255,0).
3258 (void) CopyMagickString(colorspace,name,MaxTextExtent);
3259 for (i=0; colorspace[i] != '\0'; i++)
3260 if (colorspace[i] == '(')
3262 colorspace[i--]='\0';
3263 LocaleLower(colorspace);
3264 color->matte=MagickFalse;
3265 if ((i > 0) && (colorspace[i] == 'a'))
3268 color->matte=MagickTrue;
3270 type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
3273 (void) ThrowMagickException(exception,GetMagickModule(),
3274 OptionWarning,"UnrecognizedColor","`%s'",name);
3275 return(MagickFalse);
3277 color->colorspace=(ColorspaceType) type;
3278 SetGeometryInfo(&geometry_info);
3279 flags=ParseGeometry(name+i+1,&geometry_info);
3280 scale=(MagickRealType) ScaleCharToQuantum(1);
3281 if ((flags & PercentValue) != 0)
3282 scale=(MagickRealType) (QuantumRange/100.0);
3283 if ((flags & RhoValue) != 0)
3284 color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
3285 if ((flags & SigmaValue) != 0)
3286 color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
3287 if ((flags & XiValue) != 0)
3288 color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
3289 color->opacity=(MagickRealType) OpaqueOpacity;
3290 if ((flags & PsiValue) != 0)
3292 if (color->colorspace == CMYKColorspace)
3293 color->index=(MagickRealType) RoundToQuantum(scale*
3296 if (color->matte != MagickFalse)
3297 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3298 (QuantumRange-QuantumRange*geometry_info.psi));
3300 if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
3301 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3302 (QuantumRange-QuantumRange*geometry_info.chi));
3303 if (LocaleCompare(colorspace,"gray") == 0)
3305 color->green=color->red;
3306 color->blue=color->red;
3307 if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
3308 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3309 (QuantumRange-QuantumRange*geometry_info.sigma));
3311 if (LocaleCompare(colorspace,"HSL") == 0)
3316 geometry_info.rho=fmod(fmod(scale*geometry_info.rho,360.0)+360.0,
3318 geometry_info.sigma/=100.0;
3319 geometry_info.xi/=100.0;
3320 ConvertHSLToRGB(geometry_info.rho,geometry_info.sigma,
3321 geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3322 color->colorspace=RGBColorspace;
3323 color->red=(MagickRealType) pixel.red;
3324 color->green=(MagickRealType) pixel.green;
3325 color->blue=(MagickRealType) pixel.blue;
3332 p=GetColorInfo(name,exception);
3333 if (p == (const ColorInfo *) NULL)
3334 return(MagickFalse);
3335 color->colorspace=RGBColorspace;
3336 color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3337 color->red=(MagickRealType) p->color.red;
3338 color->green=(MagickRealType) p->color.green;
3339 color->blue=(MagickRealType) p->color.blue;
3340 color->opacity=(MagickRealType) p->color.opacity;
3346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3350 % Q u e r y M a g i c k C o l o r n a m e %
3354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3356 % QueryMagickColorname() returns a named color for the given color intensity.
3357 % If an exact match is not found, a hex value is returned instead. For
3358 % example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
3361 % The format of the QueryMagickColorname method is:
3363 % MagickBooleanType QueryMagickColorname(const Image *image,
3364 % const PixelPacket *color,const ComplianceType compliance,char *name,
3365 % ExceptionInfo *exception)
3367 % A description of each parameter follows.
3369 % o image: the image.
3371 % o color: the color intensities.
3373 % o Compliance: Adhere to this color standard: SVG, X11, or XPM.
3375 % o name: Return the color name or hex value.
3377 % o exception: return any errors or warnings in this structure.
3380 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
3381 const MagickPixelPacket *color,const ComplianceType compliance,
3382 char *name,ExceptionInfo *exception)
3390 register const ColorInfo
3395 if (compliance == XPMCompliance)
3397 pixel.matte=MagickFalse;
3398 pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
3399 GetColorTuple(&pixel,MagickTrue,name);
3402 GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
3404 (void) GetColorInfo("*",exception);
3405 ResetLinkedListIterator(color_list);
3406 opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
3407 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3408 while (p != (const ColorInfo *) NULL)
3410 if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
3411 (p->color.green == color->green) && (p->color.blue == color->blue) &&
3412 (p->color.opacity == opacity))
3414 (void) CopyMagickString(name,p->name,MaxTextExtent);
3417 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3427 % U n i q u e I m a g e C o l o r s %
3431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3433 % UniqueImageColors() returns the unique colors of an image.
3435 % The format of the UniqueImageColors method is:
3437 % Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
3439 % A description of each parameter follows.
3441 % o image: the image.
3443 % o exception: return any errors or warnings in this structure.
3447 static void UniqueColorsToImage(Image *image,CubeInfo *cube_info,
3448 const NodeInfo *node_info,ExceptionInfo *exception)
3450 #define UniqueColorsImageTag "UniqueColors/Image"
3459 Traverse any children.
3461 number_children=image->matte == MagickFalse ? 8UL : 16UL;
3462 for (i=0; i < (long) number_children; i++)
3463 if (node_info->child[i] != (NodeInfo *) NULL)
3464 UniqueColorsToImage(image,cube_info,node_info->child[i],exception);
3465 if (node_info->level == (MaxTreeDepth-1))
3467 register ColorPacket
3470 register IndexPacket
3471 *__restrict indexes;
3473 register PixelPacket
3477 for (i=0; i < (long) node_info->number_unique; i++)
3479 q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception);
3480 if (q == (PixelPacket *) NULL)
3482 indexes=GetAuthenticIndexQueue(image);
3484 if (image->colorspace == CMYKColorspace)
3486 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3491 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
3492 (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse))
3493 (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress,
3494 cube_info->colors,image->client_data);
3495 cube_info->progress++;
3499 MagickExport Image *UniqueImageColors(const Image *image,
3500 ExceptionInfo *exception)
3508 cube_info=ClassifyImageColors(image,exception);
3509 if (cube_info == (CubeInfo *) NULL)
3510 return((Image *) NULL);
3511 unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
3512 if (unique_image == (Image *) NULL)
3513 return(unique_image);
3514 if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
3516 InheritException(exception,&unique_image->exception);
3517 unique_image=DestroyImage(unique_image);
3518 return((Image *) NULL);
3520 UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception);
3521 if (cube_info->colors < MaxColormapSize)
3526 quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
3527 quantize_info->number_colors=MaxColormapSize;
3528 quantize_info->dither=MagickFalse;
3529 quantize_info->tree_depth=8;
3530 (void) QuantizeImage(quantize_info,unique_image);
3531 quantize_info=DestroyQuantizeInfo(quantize_info);
3533 cube_info=DestroyCubeInfo(image,cube_info);
3534 return(unique_image);