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) &&
685 ((pixel->colorspace == HSBColorspace) ||
686 (pixel->colorspace == HSLColorspace) ||
687 (pixel->colorspace == HWBColorspace)))
689 (void) FormatMagickString(component,MaxTextExtent,"%g",
690 360.0*(QuantumScale*color));
691 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
694 if (pixel->depth > 8)
696 (void) FormatMagickString(component,MaxTextExtent,"%g%%",
697 (double) (100.0*QuantumScale*color));
698 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
701 (void) FormatMagickString(component,MaxTextExtent,"%d",
702 ScaleQuantumToChar(RoundToQuantum(color)));
703 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711 + D e f i n e I m a g e H i s t o g r a m %
715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 % DefineImageHistogram() traverses the color cube tree and notes each colormap
718 % entry. A colormap entry is any node in the color cube tree where the
719 % of unique colors is not zero.
721 % The format of the DefineImageHistogram method is:
723 % DefineImageHistogram(const Image *image,NodeInfo *node_info,
724 % ColorPacket **unique_colors)
726 % A description of each parameter follows.
728 % o image: the image.
730 % o node_info: the address of a structure of type NodeInfo which points to a
731 % node in the color cube tree that is to be pruned.
733 % o histogram: the image histogram.
736 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
737 ColorPacket **histogram)
746 Traverse any children.
748 number_children=image->matte == MagickFalse ? 8UL : 16UL;
749 for (i=0; i < (long) number_children; i++)
750 if (node_info->child[i] != (NodeInfo *) NULL)
751 DefineImageHistogram(image,node_info->child[i],histogram);
752 if (node_info->level == (MaxTreeDepth-1))
758 for (i=0; i < (long) node_info->number_unique; i++)
760 (*histogram)->pixel=p->pixel;
761 (*histogram)->index=p->index;
762 (*histogram)->count=p->count;
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774 + D e s t r o y C o l o r L i s t %
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 % DestroyColorList() deallocates memory associated with the color list.
782 % The format of the DestroyColorList method is:
784 % DestroyColorList(void)
788 static void *DestroyColorElement(void *color_info)
793 p=(ColorInfo *) color_info;
794 if (p->path != (char *) NULL)
795 p->path=DestroyString(p->path);
796 if (p->name != (char *) NULL)
797 p->name=DestroyString(p->name);
798 p=(ColorInfo *) RelinquishMagickMemory(p);
799 return((void *) NULL);
802 MagickExport void DestroyColorList(void)
804 AcquireSemaphoreInfo(&color_semaphore);
805 if (color_list != (LinkedListInfo *) NULL)
806 color_list=DestroyLinkedList(color_list,DestroyColorElement);
807 instantiate_color=MagickFalse;
808 RelinquishSemaphoreInfo(color_semaphore);
809 DestroySemaphoreInfo(&color_semaphore);
813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817 + D e s t r o y C u b e I n f o %
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
823 % DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
825 % The format of the DestroyCubeInfo method is:
827 % DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
829 % A description of each parameter follows:
831 % o image: the image.
833 % o cube_info: the address of a structure of type CubeInfo.
836 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
842 Release color cube tree storage.
844 DestroyColorCube(image,cube_info->root);
847 nodes=cube_info->node_queue->next;
848 cube_info->node_queue=(Nodes *)
849 RelinquishMagickMemory(cube_info->node_queue);
850 cube_info->node_queue=nodes;
851 } while (cube_info->node_queue != (Nodes *) NULL);
852 return((CubeInfo *) RelinquishMagickMemory(cube_info));
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 + D e s t r o y C o l o r C u b e %
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866 % DestroyColorCube() traverses the color cube tree and frees the list of
869 % The format of the DestroyColorCube method is:
871 % void DestroyColorCube(const Image *image,const NodeInfo *node_info)
873 % A description of each parameter follows.
875 % o image: the image.
877 % o node_info: the address of a structure of type NodeInfo which points to a
878 % node in the color cube tree that is to be pruned.
881 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
890 Traverse any children.
892 number_children=image->matte == MagickFalse ? 8UL : 16UL;
893 for (i=0; i < (long) number_children; i++)
894 if (node_info->child[i] != (NodeInfo *) NULL)
895 DestroyColorCube(image,node_info->child[i]);
896 if (node_info->list != (ColorPacket *) NULL)
897 node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
905 + G e t C o l o r I n f o %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911 % GetColorInfo() searches the color list for the specified name and if found
912 % returns attributes for that color.
914 % The format of the GetColorInfo method is:
916 % const PixelPacket *GetColorInfo(const char *name,
917 % ExceptionInfo *exception)
919 % A description of each parameter follows:
921 % o color_info: search the color list for the specified name and if found
922 % return attributes for that color.
924 % o name: the color name.
926 % o exception: return any errors or warnings in this structure.
929 MagickExport const ColorInfo *GetColorInfo(const char *name,
930 ExceptionInfo *exception)
933 colorname[MaxTextExtent];
935 register const ColorInfo
941 assert(exception != (ExceptionInfo *) NULL);
942 if ((color_list == (LinkedListInfo *) NULL) ||
943 (instantiate_color == MagickFalse))
944 if (InitializeColorList(exception) == MagickFalse)
945 return((const ColorInfo *) NULL);
946 if ((color_list == (LinkedListInfo *) NULL) ||
947 (IsLinkedListEmpty(color_list) != MagickFalse))
948 return((const ColorInfo *) NULL);
949 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
950 return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
952 Strip names of whitespace.
954 (void) CopyMagickString(colorname,name,MaxTextExtent);
955 for (q=colorname; *q != '\0'; q++)
957 if (isspace((int) ((unsigned char) *q)) == 0)
959 (void) CopyMagickString(q,q+1,MaxTextExtent);
963 Search for color tag.
965 AcquireSemaphoreInfo(&color_semaphore);
966 ResetLinkedListIterator(color_list);
967 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
968 while (p != (const ColorInfo *) NULL)
970 if (LocaleCompare(colorname,p->name) == 0)
972 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
974 if (p == (ColorInfo *) NULL)
975 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
976 "UnrecognizedColor","`%s'",name);
978 (void) InsertValueInLinkedList(color_list,0,
979 RemoveElementByValueFromLinkedList(color_list,p));
980 RelinquishSemaphoreInfo(color_semaphore);
985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
989 % G e t C o l o r I n f o L i s t %
993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 % GetColorInfoList() returns any colors that match the specified pattern.
997 % The format of the GetColorInfoList function is:
999 % const ColorInfo **GetColorInfoList(const char *pattern,
1000 % unsigned long *number_colors,ExceptionInfo *exception)
1002 % A description of each parameter follows:
1004 % o pattern: Specifies a pointer to a text string containing a pattern.
1006 % o number_colors: This integer returns the number of colors in the list.
1008 % o exception: return any errors or warnings in this structure.
1012 #if defined(__cplusplus) || defined(c_plusplus)
1016 static int ColorInfoCompare(const void *x,const void *y)
1022 p=(const ColorInfo **) x,
1023 q=(const ColorInfo **) y;
1024 if (LocaleCompare((*p)->path,(*q)->path) == 0)
1025 return(LocaleCompare((*p)->name,(*q)->name));
1026 return(LocaleCompare((*p)->path,(*q)->path));
1029 #if defined(__cplusplus) || defined(c_plusplus)
1033 MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
1034 unsigned long *number_colors,ExceptionInfo *exception)
1039 register const ColorInfo
1046 Allocate color list.
1048 assert(pattern != (char *) NULL);
1049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1050 assert(number_colors != (unsigned long *) NULL);
1052 p=GetColorInfo("*",exception);
1053 if (p == (const ColorInfo *) NULL)
1054 return((const ColorInfo **) NULL);
1055 colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
1056 GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1057 if (colors == (const ColorInfo **) NULL)
1058 return((const ColorInfo **) NULL);
1060 Generate color list.
1062 AcquireSemaphoreInfo(&color_semaphore);
1063 ResetLinkedListIterator(color_list);
1064 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1065 for (i=0; p != (const ColorInfo *) NULL; )
1067 if ((p->stealth == MagickFalse) &&
1068 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1070 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1072 RelinquishSemaphoreInfo(color_semaphore);
1073 qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
1074 colors[i]=(ColorInfo *) NULL;
1075 *number_colors=(unsigned long) i;
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 % G e t C o l o r L i s t %
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 % GetColorList() returns any colors that match the specified pattern.
1092 % The format of the GetColorList function is:
1094 % char **GetColorList(const char *pattern,unsigned long *number_colors,
1095 % ExceptionInfo *exception)
1097 % A description of each parameter follows:
1099 % o pattern: Specifies a pointer to a text string containing a pattern.
1101 % o number_colors: This integer returns the number of colors in the list.
1103 % o exception: return any errors or warnings in this structure.
1107 #if defined(__cplusplus) || defined(c_plusplus)
1111 static int ColorCompare(const void *x,const void *y)
1117 p=(const char **) x;
1118 q=(const char **) y;
1119 return(LocaleCompare(*p,*q));
1122 #if defined(__cplusplus) || defined(c_plusplus)
1126 MagickExport char **GetColorList(const char *pattern,
1127 unsigned long *number_colors,ExceptionInfo *exception)
1132 register const ColorInfo
1139 Allocate color list.
1141 assert(pattern != (char *) NULL);
1142 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1143 assert(number_colors != (unsigned long *) NULL);
1145 p=GetColorInfo("*",exception);
1146 if (p == (const ColorInfo *) NULL)
1147 return((char **) NULL);
1148 colors=(char **) AcquireQuantumMemory((size_t)
1149 GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
1150 if (colors == (char **) NULL)
1151 return((char **) NULL);
1153 Generate color list.
1155 AcquireSemaphoreInfo(&color_semaphore);
1156 ResetLinkedListIterator(color_list);
1157 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1158 for (i=0; p != (const ColorInfo *) NULL; )
1160 if ((p->stealth == MagickFalse) &&
1161 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
1162 colors[i++]=ConstantString(p->name);
1163 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
1165 RelinquishSemaphoreInfo(color_semaphore);
1166 qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
1167 colors[i]=(char *) NULL;
1168 *number_colors=(unsigned long) i;
1173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1177 + G e t C o l o r T u p l e %
1181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183 % GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
1184 % or hex string (e.g. #FF0000).
1186 % The format of the GetColorTuple method is:
1188 % GetColorTuple(const MagickPixelPacket *pixel,const MagickBooleanType hex,
1191 % A description of each parameter follows.
1193 % o pixel: the pixel.
1195 % o hex: A value other than zero returns the tuple in a hexidecimal format.
1197 % o tuple: Return the color tuple as this string.
1201 static void ConcatentateHexColorComponent(const MagickPixelPacket *pixel,
1202 const ChannelType channel,char *tuple)
1205 component[MaxTextExtent];
1228 case OpacityChannel:
1230 color=(MagickRealType) QuantumRange-pixel->opacity;
1241 if (pixel->depth > 32)
1243 (void) FormatMagickString(component,MaxTextExtent,"%08lX",
1244 ScaleQuantumToLong(RoundToQuantum(color)));
1245 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1248 if (pixel->depth > 16)
1250 (void) FormatMagickString(component,MaxTextExtent,"%08X",
1251 (unsigned int) ScaleQuantumToLong(RoundToQuantum(color)));
1252 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1255 if (pixel->depth > 8)
1257 (void) FormatMagickString(component,MaxTextExtent,"%04X",
1258 ScaleQuantumToShort(RoundToQuantum(color)));
1259 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1262 (void) FormatMagickString(component,MaxTextExtent,"%02X",
1263 ScaleQuantumToChar(RoundToQuantum(color)));
1264 (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
1268 MagickExport void GetColorTuple(const MagickPixelPacket *pixel,
1269 const MagickBooleanType hex,char *tuple)
1274 assert(pixel != (const MagickPixelPacket *) NULL);
1275 assert(tuple != (char *) NULL);
1276 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
1278 if (hex != MagickFalse)
1281 Convert pixel to hex color.
1283 (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
1284 ConcatentateHexColorComponent(pixel,RedChannel,tuple);
1285 ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
1286 ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
1287 if (pixel->colorspace == CMYKColorspace)
1288 ConcatentateHexColorComponent(pixel,IndexChannel,tuple);
1289 if ((pixel->matte != MagickFalse) && (pixel->opacity != OpaqueOpacity))
1290 ConcatentateHexColorComponent(pixel,OpacityChannel,tuple);
1294 Convert pixel to rgb() or cmyk() color.
1297 if (color.depth > 8)
1299 #define SVGCompliant(component) ((MagickRealType) \
1300 ScaleCharToQuantum(ScaleQuantumToChar(RoundToQuantum(component))));
1306 SVG requires color depths > 8 expressed as percentages.
1308 status=color.red == SVGCompliant(color.red);
1309 status&=color.green == SVGCompliant(color.green);
1310 status&=color.blue == SVGCompliant(color.blue);
1311 if (color.colorspace != CMYKColorspace)
1312 status&=color.index == SVGCompliant(color.index);
1313 if (color.matte != MagickFalse)
1314 status&=color.opacity == SVGCompliant(color.opacity);
1315 if (status != MagickFalse)
1318 (void) ConcatenateMagickString(tuple,MagickOptionToMnemonic(
1319 MagickColorspaceOptions,(long) color.colorspace),MaxTextExtent);
1320 if (color.matte != MagickFalse)
1321 (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
1322 (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
1323 ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
1324 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1325 ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
1326 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1327 ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
1328 if (color.colorspace == CMYKColorspace)
1330 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1331 ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple);
1333 if (color.matte != MagickFalse)
1335 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1336 ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
1338 (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 + G e t C u b e I n f o %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % GetCubeInfo() initializes the CubeInfo data structure.
1356 % The format of the GetCubeInfo method is:
1358 % cube_info=GetCubeInfo()
1360 % A description of each parameter follows.
1362 % o cube_info: A pointer to the Cube structure.
1365 static CubeInfo *GetCubeInfo(void)
1371 Initialize tree to describe color cube.
1373 cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
1374 if (cube_info == (CubeInfo *) NULL)
1375 return((CubeInfo *) NULL);
1376 (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
1378 Initialize root node.
1380 cube_info->root=GetNodeInfo(cube_info,0);
1381 if (cube_info->root == (NodeInfo *) NULL)
1382 return((CubeInfo *) NULL);
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 % G e t I m a g e H i s t o g r a m %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397 % GetImageHistogram() returns the unique colors in an image.
1399 % The format of the GetImageHistogram method is:
1401 % unsigned long GetImageHistogram(const Image *image,
1402 % unsigned long *number_colors,ExceptionInfo *exception)
1404 % A description of each parameter follows.
1406 % o image: the image.
1408 % o file: Write a histogram of the color distribution to this file handle.
1410 % o exception: return any errors or warnings in this structure.
1413 MagickExport ColorPacket *GetImageHistogram(const Image *image,
1414 unsigned long *number_colors,ExceptionInfo *exception)
1423 histogram=(ColorPacket *) NULL;
1424 cube_info=ClassifyImageColors(image,exception);
1425 if (cube_info != (CubeInfo *) NULL)
1427 histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
1428 sizeof(*histogram));
1429 if (histogram == (ColorPacket *) NULL)
1430 (void) ThrowMagickException(exception,GetMagickModule(),
1431 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1437 *number_colors=cube_info->colors;
1439 DefineImageHistogram(image,cube_info->root,&root);
1442 cube_info=DestroyCubeInfo(image,cube_info);
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 + G e t N o d e I n f o %
1455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 % GetNodeInfo() allocates memory for a new node in the color cube tree and
1458 % presets all fields to zero.
1460 % The format of the GetNodeInfo method is:
1462 % NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1464 % A description of each parameter follows.
1466 % o cube_info: A pointer to the CubeInfo structure.
1468 % o level: Specifies the level in the storage_class the node resides.
1471 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level)
1476 if (cube_info->free_nodes == 0)
1482 Allocate a new nodes of nodes.
1484 nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
1485 if (nodes == (Nodes *) NULL)
1486 return((NodeInfo *) NULL);
1487 nodes->next=cube_info->node_queue;
1488 cube_info->node_queue=nodes;
1489 cube_info->node_info=nodes->nodes;
1490 cube_info->free_nodes=NodesInAList;
1492 cube_info->free_nodes--;
1493 node_info=cube_info->node_info++;
1494 (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
1495 node_info->level=level;
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504 % G e t N u m b e r C o l o r s %
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1510 % GetNumberColors() returns the number of unique colors in an image.
1512 % The format of the GetNumberColors method is:
1514 % unsigned long GetNumberColors(const Image *image,FILE *file,
1515 % ExceptionInfo *exception)
1517 % A description of each parameter follows.
1519 % o image: the image.
1521 % o file: Write a histogram of the color distribution to this file handle.
1523 % o exception: return any errors or warnings in this structure.
1527 #if defined(__cplusplus) || defined(c_plusplus)
1531 static int HistogramCompare(const void *x,const void *y)
1537 color_1=(const ColorPacket *) x;
1538 color_2=(const ColorPacket *) y;
1539 if (color_2->pixel.red != color_1->pixel.red)
1540 return((int) color_1->pixel.red-(int) color_2->pixel.red);
1541 if (color_2->pixel.green != color_1->pixel.green)
1542 return((int) color_1->pixel.green-(int) color_2->pixel.green);
1543 if (color_2->pixel.blue != color_1->pixel.blue)
1544 return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
1545 return((int) color_2->count-(int) color_1->count);
1548 #if defined(__cplusplus) || defined(c_plusplus)
1552 MagickExport unsigned long GetNumberColors(const Image *image,FILE *file,
1553 ExceptionInfo *exception)
1555 #define HistogramImageTag "Histogram/Image"
1558 color[MaxTextExtent],
1560 tuple[MaxTextExtent];
1568 register ColorPacket
1578 if (file == (FILE *) NULL)
1583 cube_info=ClassifyImageColors(image,exception);
1584 if (cube_info != (CubeInfo *) NULL)
1585 number_colors=cube_info->colors;
1586 cube_info=DestroyCubeInfo(image,cube_info);
1587 return(number_colors);
1589 histogram=GetImageHistogram(image,&number_colors,exception);
1590 if (histogram == (ColorPacket *) NULL)
1591 return(number_colors);
1592 qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1594 GetMagickPixelPacket(image,&pixel);
1596 for (i=0; i < (long) number_colors; i++)
1598 SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel);
1599 (void) CopyMagickString(tuple,"(",MaxTextExtent);
1600 ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1601 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1602 ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1603 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1604 ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1605 if (pixel.colorspace == CMYKColorspace)
1607 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1608 ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
1610 if (pixel.matte != MagickFalse)
1612 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1613 ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
1615 (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1616 (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
1617 GetColorTuple(&pixel,MagickTrue,hex);
1618 (void) fprintf(file,MagickSizeFormat,p->count);
1619 (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
1620 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1621 (QuantumTick(i,number_colors) != MagickFalse))
1622 (void) image->progress_monitor(HistogramImageTag,i,number_colors,
1623 image->client_data);
1626 (void) fflush(file);
1627 histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
1628 return(number_colors);
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 + I n i t i a l i z e C o l o r L i s t %
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 % InitializeColorList() initializes the color list.
1644 % The format of the InitializeColorList method is:
1646 % MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1648 % A description of each parameter follows.
1650 % o exception: return any errors or warnings in this structure.
1653 static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
1655 if ((color_list == (LinkedListInfo *) NULL) &&
1656 (instantiate_color == MagickFalse))
1658 AcquireSemaphoreInfo(&color_semaphore);
1659 if ((color_list == (LinkedListInfo *) NULL) &&
1660 (instantiate_color == MagickFalse))
1662 (void) LoadColorLists(ColorFilename,exception);
1663 instantiate_color=MagickTrue;
1665 RelinquishSemaphoreInfo(color_semaphore);
1667 return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 + I s C o l o r S i m i l a r %
1679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 % IsColorSimilar() returns MagickTrue if the distance between two colors is
1682 % less than the specified distance in a linear three dimensional color space.
1683 % This method is used by ColorFloodFill() and other algorithms which
1684 % compare two colors.
1686 % The format of the IsColorSimilar method is:
1688 % void IsColorSimilar(const Image *image,const PixelPacket *p,
1689 % const PixelPacket *q)
1691 % A description of each parameter follows:
1693 % o image: the image.
1701 static inline double MagickMax(const double x,const double y)
1708 MagickExport MagickBooleanType IsColorSimilar(const Image *image,
1709 const PixelPacket *p,const PixelPacket *q)
1715 register MagickRealType
1720 if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
1721 return(IsColorEqual(p,q));
1722 fuzz=3.0*MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,
1726 if (image->matte != MagickFalse)
1728 alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
1729 beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
1731 pixel=alpha*p->red-beta*q->red;
1732 distance=pixel*pixel;
1733 if (distance > fuzz)
1734 return(MagickFalse);
1735 pixel=alpha*p->green-beta*q->green;
1736 distance+=pixel*pixel;
1737 if (distance > fuzz)
1738 return(MagickFalse);
1739 pixel=alpha*p->blue-beta*q->blue;
1740 distance+=pixel*pixel;
1741 if (distance > fuzz)
1742 return(MagickFalse);
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751 % I s G r a y I m a g e %
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1757 % IsGrayImage() returns MagickTrue if all the pixels in the image have the
1758 % same red, green, and blue intensities.
1760 % The format of the IsGrayImage method is:
1762 % MagickBooleanType IsGrayImage(const Image *image,
1763 % ExceptionInfo *exception)
1765 % A description of each parameter follows:
1767 % o image: the image.
1769 % o exception: return any errors or warnings in this structure.
1772 MagickExport MagickBooleanType IsGrayImage(const Image *image,
1773 ExceptionInfo *exception)
1778 register const PixelPacket
1781 assert(image != (Image *) NULL);
1782 assert(image->signature == MagickSignature);
1783 if (image->debug != MagickFalse)
1784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1785 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1786 (image->type == GrayscaleMatteType))
1788 if (image->colorspace == CMYKColorspace)
1789 return(MagickFalse);
1791 switch (image->storage_class)
1794 case UndefinedClass:
1805 image_view=AcquireCacheView(image);
1806 for (y=0; y < (long) image->rows; y++)
1808 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1809 if (p == (const PixelPacket *) NULL)
1811 for (x=0; x < (long) image->columns; x++)
1813 if (IsGrayPixel(p) == MagickFalse)
1818 if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1822 if (type == UndefinedType)
1825 image_view=DestroyCacheView(image_view);
1834 for (i=0; i < (long) image->colors; i++)
1836 if (IsGrayPixel(p) == MagickFalse)
1841 if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1848 if (type == UndefinedType)
1849 return(MagickFalse);
1850 ((Image *) image)->type=type;
1851 if ((type == GrayscaleType) && (image->matte != MagickFalse))
1852 ((Image *) image)->type=GrayscaleMatteType;
1857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861 % I s H i s t o g r a m I m a g e %
1865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867 % IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
1870 % The format of the IsHistogramImage method is:
1872 % MagickBooleanType IsHistogramImage(const Image *image,
1873 % ExceptionInfo *exception)
1875 % A description of each parameter follows.
1877 % o image: the image.
1879 % o exception: return any errors or warnings in this structure.
1882 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
1883 ExceptionInfo *exception)
1885 #define MaximumUniqueColors 1024
1897 register const IndexPacket
1900 register const PixelPacket
1920 assert(image != (Image *) NULL);
1921 assert(image->signature == MagickSignature);
1922 if (image->debug != MagickFalse)
1923 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1924 if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1926 if (image->storage_class == PseudoClass)
1927 return(MagickFalse);
1929 Initialize color description tree.
1931 cube_info=GetCubeInfo();
1932 if (cube_info == (CubeInfo *) NULL)
1934 (void) ThrowMagickException(exception,GetMagickModule(),
1935 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1936 return(MagickFalse);
1938 GetMagickPixelPacket(image,&pixel);
1939 GetMagickPixelPacket(image,&target);
1940 image_view=AcquireCacheView(image);
1941 for (y=0; y < (long) image->rows; y++)
1943 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1944 if (p == (const PixelPacket *) NULL)
1946 indexes=GetCacheViewVirtualIndexQueue(image_view);
1947 for (x=0; x < (long) image->columns; x++)
1950 Start at the root and proceed level by level.
1952 node_info=cube_info->root;
1953 index=MaxTreeDepth-1;
1954 for (level=1; level < MaxTreeDepth; level++)
1956 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1957 id=ColorToNodeId(image,&pixel,index);
1958 if (node_info->child[id] == (NodeInfo *) NULL)
1960 node_info->child[id]=GetNodeInfo(cube_info,level);
1961 if (node_info->child[id] == (NodeInfo *) NULL)
1963 (void) ThrowMagickException(exception,GetMagickModule(),
1964 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1969 node_info=node_info->child[id];
1972 if (level < MaxTreeDepth)
1974 for (i=0; i < (long) node_info->number_unique; i++)
1976 SetMagickPixelPacket(image,&node_info->list[i].pixel,
1977 &node_info->list[i].index,&target);
1978 if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
1981 if (i < (long) node_info->number_unique)
1982 node_info->list[i].count++;
1986 Add this unique color to the color list.
1988 if (node_info->number_unique == 0)
1989 node_info->list=(ColorPacket *) AcquireMagickMemory(
1990 sizeof(*node_info->list));
1992 node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
1993 (size_t) (i+1),sizeof(*node_info->list));
1994 if (node_info->list == (ColorPacket *) NULL)
1996 (void) ThrowMagickException(exception,GetMagickModule(),
1997 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2001 node_info->list[i].pixel=(*p);
2002 if ((image->colorspace == CMYKColorspace) ||
2003 (image->storage_class == PseudoClass))
2004 node_info->list[i].index=indexes[x];
2005 node_info->list[i].count=1;
2006 node_info->number_unique++;
2007 cube_info->colors++;
2008 if (cube_info->colors > MaximumUniqueColors)
2013 if (x < (long) image->columns)
2016 image_view=DestroyCacheView(image_view);
2017 cube_info=DestroyCubeInfo(image,cube_info);
2018 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2026 + I s I m a g e S i m i l a r %
2030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2032 % IsImageSimilar() returns true if the target is similar to a region of the
2035 % The format of the IsImageSimilar method is:
2037 % MagickBooleanType IsImageSimilar(const Image *image,
2038 % const Image *target_image,long *x_offset,long *y_offset,
2039 % ExceptionInfo *exception)
2041 % A description of each parameter follows:
2043 % o image: the image.
2045 % o target_image: the target image.
2047 % o x_offset: On input the starting x position to search for a match;
2048 % on output the x position of the first match found.
2050 % o y_offset: On input the starting y position to search for a match;
2051 % on output the y position of the first match found.
2053 % o exception: return any errors or warnings in this structure.
2056 MagickExport MagickBooleanType IsImageSimilar(const Image *image,
2057 const Image *target_image,long *x_offset,long *y_offset,
2058 ExceptionInfo *exception)
2060 #define SearchImageText " Searching image... "
2073 register const PixelPacket
2077 register const IndexPacket
2089 assert(image != (Image *) NULL);
2090 assert(image->signature == MagickSignature);
2091 if (image->debug != MagickFalse)
2092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2093 assert(target_image != (Image *) NULL);
2094 assert(target_image->signature == MagickSignature);
2095 assert(x_offset != (long *) NULL);
2096 assert(y_offset != (long *) NULL);
2097 assert(exception != (ExceptionInfo *) NULL);
2099 GetMagickPixelPacket(image,&pixel);
2100 GetMagickPixelPacket(image,&target);
2101 image_view=AcquireCacheView(image);
2102 target_view=AcquireCacheView(target_image);
2103 for (y=(*y_offset); y < (long) image->rows; y++)
2105 for (x=y == 0 ? *x_offset : 0; x < (long) image->columns; x++)
2107 for (j=0; j < (long) target_image->rows; j++)
2109 for (i=0; i < (long) target_image->columns; i++)
2111 p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
2112 indexes=GetCacheViewVirtualIndexQueue(image_view);
2113 SetMagickPixelPacket(image,p,indexes,&pixel);
2114 q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
2115 target_indexes=GetCacheViewVirtualIndexQueue(target_view);
2116 SetMagickPixelPacket(image,q,target_indexes,&target);
2117 if (IsMagickColorSimilar(&pixel,&target) == MagickFalse)
2120 if (i < (long) target_image->columns)
2123 if (j == (long) target_image->rows)
2126 if (x < (long) image->columns)
2128 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
2129 (QuantumTick(y,image->rows) != MagickFalse))
2131 status=image->progress_monitor(SearchImageText,y,image->rows,
2132 image->client_data);
2133 if (status == MagickFalse)
2137 target_view=DestroyCacheView(target_view);
2138 image_view=DestroyCacheView(image_view);
2141 return(y < (long) image->rows ? MagickTrue : MagickFalse);
2145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149 + I s M a g i c k C o l o r S i m i l a r %
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155 % IsMagickColorSimilar() returns true if the distance between two colors is
2156 % less than the specified distance in a linear three dimensional color space.
2157 % This method is used by ColorFloodFill() and other algorithms which
2158 % compare two colors.
2160 % The format of the IsMagickColorSimilar method is:
2162 % MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2163 % const MagickPixelPacket *q)
2165 % A description of each parameter follows:
2172 MagickExport MagickBooleanType IsMagickColorSimilar(const MagickPixelPacket *p,
2173 const MagickPixelPacket *q)
2179 register MagickRealType
2184 if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
2185 return(IsMagickColorEqual(p,q));
2187 fuzz=MagickMax(q->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2190 fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(p->fuzz,MagickSQ1_2);
2192 fuzz=3.0*MagickMax(p->fuzz,MagickSQ1_2)*MagickMax(q->fuzz,MagickSQ1_2);
2194 if (p->matte != MagickFalse)
2195 alpha=(MagickRealType) (QuantumScale*(QuantumRange-p->opacity));
2197 if (q->matte != MagickFalse)
2198 beta=(MagickRealType) (QuantumScale*(QuantumRange-q->opacity));
2199 if (p->colorspace == CMYKColorspace)
2201 alpha*=(MagickRealType) (QuantumScale*(QuantumRange-p->index));
2202 beta*=(MagickRealType) (QuantumScale*(QuantumRange-q->index));
2204 pixel=alpha*p->red-beta*q->red;
2205 if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
2206 (p->colorspace == HWBColorspace))
2208 if (fabs(p->red-q->red) > (QuantumRange/2))
2210 if (p->red > (QuantumRange/2))
2211 pixel=alpha*(p->red-QuantumRange)-beta*q->red;
2213 pixel=alpha*p->red-beta*(q->red-QuantumRange);
2217 distance=pixel*pixel;
2218 if (distance > fuzz)
2219 return(MagickFalse);
2220 pixel=alpha*p->green-beta*q->green;
2221 distance+=pixel*pixel;
2222 if (distance > fuzz)
2223 return(MagickFalse);
2224 pixel=alpha*p->blue-beta*q->blue;
2225 distance+=pixel*pixel;
2226 if (distance > fuzz)
2227 return(MagickFalse);
2228 pixel=p->opacity-q->opacity;
2229 distance+=pixel*pixel;
2230 if (distance > fuzz)
2231 return(MagickFalse);
2236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 % I s M o n o c h r o m e I m a g e %
2244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2246 % IsMonochromeImage() returns MagickTrue if all the pixels in the image have
2247 % the same red, green, and blue intensities and the intensity is either
2248 % 0 or QuantumRange.
2250 % The format of the IsMonochromeImage method is:
2252 % MagickBooleanType IsMonochromeImage(const Image *image,
2253 % ExceptionInfo *exception)
2255 % A description of each parameter follows:
2257 % o image: the image.
2259 % o exception: return any errors or warnings in this structure.
2262 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
2263 ExceptionInfo *exception)
2268 register const PixelPacket
2271 assert(image != (Image *) NULL);
2272 assert(image->signature == MagickSignature);
2273 if (image->debug != MagickFalse)
2274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2275 if (image->type == BilevelType)
2277 if (image->colorspace == CMYKColorspace)
2278 return(MagickFalse);
2280 switch (image->storage_class)
2283 case UndefinedClass:
2294 image_view=AcquireCacheView(image);
2295 for (y=0; y < (long) image->rows; y++)
2297 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2298 if (p == (const PixelPacket *) NULL)
2300 for (x=0; x < (long) image->columns; x++)
2302 if (IsMonochromePixel(p) == MagickFalse)
2309 if (type == UndefinedType)
2312 image_view=DestroyCacheView(image_view);
2313 if (y == (long) image->rows)
2314 ((Image *) image)->type=BilevelType;
2323 for (i=0; i < (long) image->colors; i++)
2325 if (IsMonochromePixel(p) == MagickFalse)
2335 if (type == UndefinedType)
2336 return(MagickFalse);
2337 ((Image *) image)->type=type;
2342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346 + I s O p a c i t y S i m i l a r %
2350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 % IsOpacitySimilar() returns true if the distance between two opacity
2353 % values is less than the specified distance in a linear color space. This
2354 % method is used by MatteFloodFill() and other algorithms which compare
2355 % two opacity values.
2357 % The format of the IsOpacitySimilar method is:
2359 % void IsOpacitySimilar(const Image *image,const PixelPacket *p,
2360 % const PixelPacket *q)
2362 % A description of each parameter follows:
2364 % o image: the image.
2371 MagickExport MagickBooleanType IsOpacitySimilar(const Image *image,
2372 const PixelPacket *p,const PixelPacket *q)
2378 register MagickRealType
2381 if (image->matte == MagickFalse)
2383 if (p->opacity == q->opacity)
2385 fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
2386 pixel=(MagickRealType) p->opacity-(MagickRealType) q->opacity;
2387 distance=pixel*pixel;
2388 if (distance > fuzz)
2389 return(MagickFalse);
2394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2398 % I s O p a q u e I m a g e %
2402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404 % IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
2405 % an opacity value other than opaque (0).
2407 % The format of the IsOpaqueImage method is:
2409 % MagickBooleanType IsOpaqueImage(const Image *image,
2410 % ExceptionInfo *exception)
2412 % A description of each parameter follows:
2414 % o image: the image.
2416 % o exception: return any errors or warnings in this structure.
2419 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
2420 ExceptionInfo *exception)
2425 register const PixelPacket
2435 Determine if image is opaque.
2437 assert(image != (Image *) NULL);
2438 assert(image->signature == MagickSignature);
2439 if (image->debug != MagickFalse)
2440 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2441 if (image->matte == MagickFalse)
2443 image_view=AcquireCacheView(image);
2444 for (y=0; y < (long) image->rows; y++)
2446 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2447 if (p == (const PixelPacket *) NULL)
2449 for (x=0; x < (long) image->columns; x++)
2451 if (p->opacity != OpaqueOpacity)
2455 if (x < (long) image->columns)
2458 image_view=DestroyCacheView(image_view);
2459 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467 % I s P a l e t t e I m a g e %
2471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473 % IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
2474 % unique colors or less.
2476 % The format of the IsPaletteImage method is:
2478 % MagickBooleanType IsPaletteImage(const Image *image,
2479 % ExceptionInfo *exception)
2481 % A description of each parameter follows.
2483 % o image: the image.
2485 % o exception: return any errors or warnings in this structure.
2488 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
2489 ExceptionInfo *exception)
2501 register const IndexPacket
2504 register const PixelPacket
2524 assert(image != (Image *) NULL);
2525 assert(image->signature == MagickSignature);
2526 if (image->debug != MagickFalse)
2527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2528 if ((image->storage_class == PseudoClass) && (image->colors <= 256))
2530 if (image->storage_class == PseudoClass)
2531 return(MagickFalse);
2533 Initialize color description tree.
2535 cube_info=GetCubeInfo();
2536 if (cube_info == (CubeInfo *) NULL)
2538 (void) ThrowMagickException(exception,GetMagickModule(),
2539 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2540 return(MagickFalse);
2542 GetMagickPixelPacket(image,&pixel);
2543 GetMagickPixelPacket(image,&target);
2544 image_view=AcquireCacheView(image);
2545 for (y=0; y < (long) image->rows; y++)
2547 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2548 if (p == (const PixelPacket *) NULL)
2550 indexes=GetCacheViewVirtualIndexQueue(image_view);
2551 for (x=0; x < (long) image->columns; x++)
2554 Start at the root and proceed level by level.
2556 node_info=cube_info->root;
2557 index=MaxTreeDepth-1;
2558 for (level=1; level < MaxTreeDepth; level++)
2560 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2561 id=ColorToNodeId(image,&pixel,index);
2562 if (node_info->child[id] == (NodeInfo *) NULL)
2564 node_info->child[id]=GetNodeInfo(cube_info,level);
2565 if (node_info->child[id] == (NodeInfo *) NULL)
2567 (void) ThrowMagickException(exception,GetMagickModule(),
2568 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2573 node_info=node_info->child[id];
2576 if (level < MaxTreeDepth)
2578 for (i=0; i < (long) node_info->number_unique; i++)
2580 SetMagickPixelPacket(image,&node_info->list[i].pixel,
2581 &node_info->list[i].index,&target);
2582 if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
2585 if (i < (long) node_info->number_unique)
2586 node_info->list[i].count++;
2590 Add this unique color to the color list.
2592 if (node_info->number_unique == 0)
2593 node_info->list=(ColorPacket *) AcquireMagickMemory(
2594 sizeof(*node_info->list));
2596 node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
2597 (size_t) (i+1),sizeof(*node_info->list));
2598 if (node_info->list == (ColorPacket *) NULL)
2600 (void) ThrowMagickException(exception,GetMagickModule(),
2601 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2605 node_info->list[i].pixel=(*p);
2606 if ((image->colorspace == CMYKColorspace) ||
2607 (image->storage_class == PseudoClass))
2608 node_info->list[i].index=indexes[x];
2609 node_info->list[i].count=1;
2610 node_info->number_unique++;
2611 cube_info->colors++;
2612 if (cube_info->colors > 256)
2617 if (x < (long) image->columns)
2620 image_view=DestroyCacheView(image_view);
2621 cube_info=DestroyCubeInfo(image,cube_info);
2622 return(y < (long) image->rows ? MagickFalse : MagickTrue);
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630 % L i s t C o l o r I n f o %
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 % ListColorInfo() lists color names to the specified file. Color names
2637 % are a convenience. Rather than defining a color by its red, green, and
2638 % blue intensities just use a color name such as white, blue, or yellow.
2640 % The format of the ListColorInfo method is:
2642 % MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
2644 % A description of each parameter follows.
2646 % o file: List color names to this file handle.
2648 % o exception: return any errors or warnings in this structure.
2651 MagickExport MagickBooleanType ListColorInfo(FILE *file,
2652 ExceptionInfo *exception)
2655 tuple[MaxTextExtent];
2670 List name and attributes of each color in the list.
2672 if (file == (const FILE *) NULL)
2674 color_info=GetColorInfoList("*",&number_colors,exception);
2675 if (color_info == (const ColorInfo **) NULL)
2676 return(MagickFalse);
2677 path=(const char *) NULL;
2678 for (i=0; i < (long) number_colors; i++)
2680 if (color_info[i]->stealth != MagickFalse)
2682 if ((path == (const char *) NULL) ||
2683 (LocaleCompare(path,color_info[i]->path) != 0))
2685 if (color_info[i]->path != (char *) NULL)
2686 (void) fprintf(file,"\nPath: %s\n\n",color_info[i]->path);
2687 (void) fprintf(file,"Name Color "
2689 (void) fprintf(file,"-------------------------------------------------"
2690 "------------------------------\n");
2692 path=color_info[i]->path;
2693 (void) fprintf(file,"%-21.21s ",color_info[i]->name);
2694 GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
2695 (void) fprintf(file,"%-45.45s ",tuple);
2696 if ((color_info[i]->compliance & SVGCompliance) != 0)
2697 (void) fprintf(file,"SVG ");
2698 if ((color_info[i]->compliance & X11Compliance) != 0)
2699 (void) fprintf(file,"X11 ");
2700 if ((color_info[i]->compliance & XPMCompliance) != 0)
2701 (void) fprintf(file,"XPM ");
2702 (void) fprintf(file,"\n");
2704 color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
2705 (void) fflush(file);
2710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714 + L o a d C o l o r L i s t %
2718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720 % LoadColorList() loads the color configuration file which provides a mapping
2721 % between color attributes and a color name.
2723 % The format of the LoadColorList method is:
2725 % MagickBooleanType LoadColorList(const char *xml,const char *filename,
2726 % const unsigned long depth,ExceptionInfo *exception)
2728 % A description of each parameter follows:
2730 % o xml: The color list in XML format.
2732 % o filename: The color list filename.
2734 % o depth: depth of <include /> statements.
2736 % o exception: return any errors or warnings in this structure.
2739 static MagickBooleanType LoadColorList(const char *xml,const char *filename,
2740 const unsigned long depth,ExceptionInfo *exception)
2743 keyword[MaxTextExtent],
2756 Load the color map file.
2758 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2759 "Loading color file \"%s\" ...",filename);
2760 if (xml == (char *) NULL)
2761 return(MagickFalse);
2762 if (color_list == (LinkedListInfo *) NULL)
2764 color_list=NewLinkedList(0);
2765 if (color_list == (LinkedListInfo *) NULL)
2767 ThrowFileException(exception,ResourceLimitError,
2768 "MemoryAllocationFailed",filename);
2769 return(MagickFalse);
2773 color_info=(ColorInfo *) NULL;
2774 token=AcquireString(xml);
2775 for (q=(char *) xml; *q != '\0'; )
2780 GetMagickToken(q,&q,token);
2783 (void) CopyMagickString(keyword,token,MaxTextExtent);
2784 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2789 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2790 GetMagickToken(q,&q,token);
2793 if (LocaleNCompare(keyword,"<!--",4) == 0)
2798 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2799 GetMagickToken(q,&q,token);
2802 if (LocaleCompare(keyword,"<include") == 0)
2807 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2809 (void) CopyMagickString(keyword,token,MaxTextExtent);
2810 GetMagickToken(q,&q,token);
2813 GetMagickToken(q,&q,token);
2814 if (LocaleCompare(keyword,"file") == 0)
2817 (void) ThrowMagickException(exception,GetMagickModule(),
2818 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2822 path[MaxTextExtent],
2825 GetPathComponent(filename,HeadPath,path);
2827 (void) ConcatenateMagickString(path,DirectorySeparator,
2829 if (*token == *DirectorySeparator)
2830 (void) CopyMagickString(path,token,MaxTextExtent);
2832 (void) ConcatenateMagickString(path,token,MaxTextExtent);
2833 xml=FileToString(path,~0,exception);
2834 if (xml != (char *) NULL)
2836 status=LoadColorList(xml,path,depth+1,exception);
2837 xml=(char *) RelinquishMagickMemory(xml);
2844 if (LocaleCompare(keyword,"<color") == 0)
2849 color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
2850 if (color_info == (ColorInfo *) NULL)
2851 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2852 (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
2853 color_info->path=ConstantString(filename);
2854 color_info->signature=MagickSignature;
2857 if (color_info == (ColorInfo *) NULL)
2859 if (LocaleCompare(keyword,"/>") == 0)
2861 status=AppendValueToLinkedList(color_list,color_info);
2862 if (status == MagickFalse)
2863 (void) ThrowMagickException(exception,GetMagickModule(),
2864 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2866 color_info=(ColorInfo *) NULL;
2868 GetMagickToken(q,(const char **) NULL,token);
2871 GetMagickToken(q,&q,token);
2872 GetMagickToken(q,&q,token);
2878 if (LocaleCompare((char *) keyword,"color") == 0)
2880 (void) QueryMagickColor(token,&color_info->color,exception);
2883 if (LocaleCompare((char *) keyword,"compliance") == 0)
2888 compliance=color_info->compliance;
2889 if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
2890 compliance|=SVGCompliance;
2891 if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
2892 compliance|=X11Compliance;
2893 if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
2894 compliance|=XPMCompliance;
2895 color_info->compliance=(ComplianceType) compliance;
2903 if (LocaleCompare((char *) keyword,"name") == 0)
2905 color_info->name=ConstantString(token);
2913 if (LocaleCompare((char *) keyword,"stealth") == 0)
2915 color_info->stealth=IsMagickTrue(token);
2924 token=(char *) RelinquishMagickMemory(token);
2929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933 % L o a d C o l o r L i s t s %
2937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939 % LoadColorList() loads one or more color configuration file which provides a
2940 % mapping between color attributes and a color name.
2942 % The format of the LoadColorLists method is:
2944 % MagickBooleanType LoadColorLists(const char *filename,
2945 % ExceptionInfo *exception)
2947 % A description of each parameter follows:
2949 % o filename: the font file name.
2951 % o exception: return any errors or warnings in this structure.
2954 static MagickBooleanType LoadColorLists(const char *filename,
2955 ExceptionInfo *exception)
2957 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
2958 return(LoadColorList(ColorMap,"built-in",0,exception));
2970 options=GetConfigureOptions(filename,exception);
2971 option=(const StringInfo *) GetNextValueInLinkedList(options);
2972 while (option != (const StringInfo *) NULL)
2974 status|=LoadColorList((const char *) GetStringInfoDatum(option),
2975 GetStringInfoPath(option),0,exception);
2976 option=(const StringInfo *) GetNextValueInLinkedList(options);
2978 options=DestroyConfigureOptions(options);
2979 if ((color_list == (LinkedListInfo *) NULL) ||
2980 (IsLinkedListEmpty(color_list) != MagickFalse))
2981 status|=LoadColorList(ColorMap,"built-in",0,exception);
2982 return(status != 0 ? MagickTrue : MagickFalse);
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991 % Q u e r y C o l o r D a t a b a s e %
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997 % QueryColorDatabase() returns the red, green, blue, and opacity intensities
2998 % for a given color name.
3000 % The format of the QueryColorDatabase method is:
3002 % MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
3003 % ExceptionInfo *exception)
3005 % A description of each parameter follows:
3007 % o name: the color name (e.g. white, blue, yellow).
3009 % o color: the red, green, blue, and opacity intensities values of the
3010 % named color in this structure.
3012 % o exception: return any errors or warnings in this structure.
3016 static inline double MagickMin(const double x,const double y)
3023 MagickExport MagickBooleanType QueryColorDatabase(const char *name,
3024 PixelPacket *color,ExceptionInfo *exception)
3032 status=QueryMagickColor(name,&pixel,exception);
3033 color->opacity=RoundToQuantum(pixel.opacity);
3034 if (pixel.colorspace == CMYKColorspace)
3036 color->red=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3037 QuantumRange,(MagickRealType) (QuantumScale*pixel.red*(QuantumRange-
3038 pixel.index)+pixel.index))));
3039 color->green=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3040 QuantumRange,(MagickRealType) (QuantumScale*pixel.green*(QuantumRange-
3041 pixel.index)+pixel.index))));
3042 color->blue=RoundToQuantum((MagickRealType) (QuantumRange-MagickMin(
3043 QuantumRange,(MagickRealType) (QuantumScale*pixel.blue*(QuantumRange-
3044 pixel.index)+pixel.index))));
3047 color->red=RoundToQuantum(pixel.red);
3048 color->green=RoundToQuantum(pixel.green);
3049 color->blue=RoundToQuantum(pixel.blue);
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3058 % Q u e r y C o l o r n a m e %
3062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3064 % QueryColorname() returns a named color for the given color intensity. If
3065 % an exact match is not found, a rgb() color is returned instead.
3067 % The format of the QueryColorname method is:
3069 % MagickBooleanType QueryColorname(const Image *image,
3070 % const PixelPacket *color,const ComplianceType compliance,char *name,
3071 % ExceptionInfo *exception)
3073 % A description of each parameter follows.
3075 % o image: the image.
3077 % o color: the color intensities.
3079 % o compliance: Adhere to this color standard: SVG, X11, or XPM.
3081 % o name: Return the color name or hex value.
3083 % o exception: return any errors or warnings in this structure.
3086 MagickExport MagickBooleanType QueryColorname(const Image *image,
3087 const PixelPacket *color,const ComplianceType compliance,char *name,
3088 ExceptionInfo *exception)
3093 GetMagickPixelPacket(image,&pixel);
3094 SetMagickPixelPacket(image,color,(IndexPacket *) NULL,&pixel);
3095 return(QueryMagickColorname(image,&pixel,compliance,name,exception));
3099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3103 % Q u e r y M a g i c k C o l o r %
3107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3109 % QueryMagickColor() returns the red, green, blue, and opacity intensities
3110 % for a given color name.
3112 % The format of the QueryMagickColor method is:
3114 % MagickBooleanType QueryMagickColor(const char *name,
3115 % MagickPixelPacket *color,ExceptionInfo *exception)
3117 % A description of each parameter follows:
3119 % o name: the color name (e.g. white, blue, yellow).
3121 % o color: the red, green, blue, and opacity intensities values of the
3122 % named color in this structure.
3124 % o exception: return any errors or warnings in this structure.
3127 MagickExport MagickBooleanType QueryMagickColor(const char *name,
3128 MagickPixelPacket *color,ExceptionInfo *exception)
3142 register const ColorInfo
3149 Initialize color return value.
3151 assert(name != (const char *) NULL);
3152 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
3153 assert(color != (MagickPixelPacket *) NULL);
3154 GetMagickPixelPacket((Image *) NULL,color);
3155 if ((name == (char *) NULL) || (*name == '\0'))
3156 name=BackgroundColor;
3157 while (isspace((int) ((unsigned char) *name)) != 0)
3177 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
3179 for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
3184 pixel.red=pixel.green;
3185 pixel.green=pixel.blue;
3187 for (i=(long) (n/3-1); i >= 0; i--)
3191 if ((c >= '0') && (c <= '9'))
3192 pixel.blue|=(int) (c-'0');
3194 if ((c >= 'A') && (c <= 'F'))
3195 pixel.blue|=(int) c-((int) 'A'-10);
3197 if ((c >= 'a') && (c <= 'f'))
3198 pixel.blue|=(int) c-((int) 'a'-10);
3200 return(MagickFalse);
3202 } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3209 (void) ThrowMagickException(exception,GetMagickModule(),
3210 OptionWarning,"UnrecognizedColor","`%s'",name);
3211 return(MagickFalse);
3215 pixel.red=pixel.green;
3216 pixel.green=pixel.blue;
3217 pixel.blue=pixel.opacity;
3219 for (i=(long) (n/4-1); i >= 0; i--)
3223 if ((c >= '0') && (c <= '9'))
3224 pixel.opacity|=(int) (c-'0');
3226 if ((c >= 'A') && (c <= 'F'))
3227 pixel.opacity|=(int) c-((int) 'A'-10);
3229 if ((c >= 'a') && (c <= 'f'))
3230 pixel.opacity|=(int) c-((int) 'a'-10);
3232 return(MagickFalse);
3234 } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
3237 color->colorspace=RGBColorspace;
3238 color->matte=MagickFalse;
3239 range=GetQuantumRange(depth);
3240 color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
3241 color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
3242 color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
3243 color->opacity=(MagickRealType) OpaqueOpacity;
3246 color->matte=MagickTrue;
3247 color->opacity=(MagickRealType) (QuantumRange-ScaleAnyToQuantum(
3248 pixel.opacity,range));
3253 if (strchr(name,'(') != (char *) NULL)
3256 colorspace[MaxTextExtent];
3259 Parse color of the form rgb(100,255,0).
3261 (void) CopyMagickString(colorspace,name,MaxTextExtent);
3262 for (i=0; colorspace[i] != '\0'; i++)
3263 if (colorspace[i] == '(')
3265 colorspace[i--]='\0';
3266 LocaleLower(colorspace);
3267 color->matte=MagickFalse;
3268 if ((i > 0) && (colorspace[i] == 'a'))
3271 color->matte=MagickTrue;
3273 type=ParseMagickOption(MagickColorspaceOptions,MagickFalse,colorspace);
3276 (void) ThrowMagickException(exception,GetMagickModule(),
3277 OptionWarning,"UnrecognizedColor","`%s'",name);
3278 return(MagickFalse);
3280 color->colorspace=(ColorspaceType) type;
3281 SetGeometryInfo(&geometry_info);
3282 flags=ParseGeometry(name+i+1,&geometry_info);
3283 scale=(MagickRealType) ScaleCharToQuantum(1);
3284 if ((flags & PercentValue) != 0)
3285 scale=(MagickRealType) (QuantumRange/100.0);
3286 if ((flags & RhoValue) != 0)
3287 color->red=(MagickRealType) RoundToQuantum(scale*geometry_info.rho);
3288 if ((flags & SigmaValue) != 0)
3289 color->green=(MagickRealType) RoundToQuantum(scale*geometry_info.sigma);
3290 if ((flags & XiValue) != 0)
3291 color->blue=(MagickRealType) RoundToQuantum(scale*geometry_info.xi);
3292 color->opacity=(MagickRealType) OpaqueOpacity;
3293 if ((flags & PsiValue) != 0)
3295 if (color->colorspace == CMYKColorspace)
3296 color->index=(MagickRealType) RoundToQuantum(scale*
3299 if (color->matte != MagickFalse)
3300 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3301 (QuantumRange-QuantumRange*geometry_info.psi));
3303 if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
3304 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3305 (QuantumRange-QuantumRange*geometry_info.chi));
3306 if (LocaleCompare(colorspace,"gray") == 0)
3308 color->green=color->red;
3309 color->blue=color->red;
3310 if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
3311 color->opacity=(MagickRealType) RoundToQuantum((MagickRealType)
3312 (QuantumRange-QuantumRange*geometry_info.sigma));
3314 if (LocaleCompare(colorspace,"HSB") == 0)
3319 geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3322 if ((flags & PercentValue) != 0)
3324 geometry_info.sigma*=scale;
3325 geometry_info.xi*=scale;
3326 ConvertHSBToRGB(geometry_info.rho,geometry_info.sigma,
3327 geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3328 color->colorspace=RGBColorspace;
3329 color->red=(MagickRealType) pixel.red;
3330 color->green=(MagickRealType) pixel.green;
3331 color->blue=(MagickRealType) pixel.blue;
3333 if (LocaleCompare(colorspace,"HSL") == 0)
3338 geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3341 if ((flags & PercentValue) != 0)
3343 geometry_info.sigma*=scale;
3344 geometry_info.xi*=scale;
3345 ConvertHSLToRGB(geometry_info.rho,geometry_info.sigma,
3346 geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3347 color->colorspace=RGBColorspace;
3348 color->red=(MagickRealType) pixel.red;
3349 color->green=(MagickRealType) pixel.green;
3350 color->blue=(MagickRealType) pixel.blue;
3352 if (LocaleCompare(colorspace,"HWB") == 0)
3357 geometry_info.rho=fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
3360 if ((flags & PercentValue) != 0)
3362 geometry_info.sigma*=scale;
3363 geometry_info.xi*=scale;
3364 ConvertHWBToRGB(geometry_info.rho,geometry_info.sigma,
3365 geometry_info.xi,&pixel.red,&pixel.green,&pixel.blue);
3366 color->colorspace=RGBColorspace;
3367 color->red=(MagickRealType) pixel.red;
3368 color->green=(MagickRealType) pixel.green;
3369 color->blue=(MagickRealType) pixel.blue;
3376 p=GetColorInfo(name,exception);
3377 if (p == (const ColorInfo *) NULL)
3378 return(MagickFalse);
3379 color->colorspace=RGBColorspace;
3380 color->matte=p->color.opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3381 color->red=(MagickRealType) p->color.red;
3382 color->green=(MagickRealType) p->color.green;
3383 color->blue=(MagickRealType) p->color.blue;
3384 color->opacity=(MagickRealType) p->color.opacity;
3390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3394 % Q u e r y M a g i c k C o l o r n a m e %
3398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3400 % QueryMagickColorname() returns a named color for the given color intensity.
3401 % If an exact match is not found, a hex value is returned instead. For
3402 % example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
3405 % The format of the QueryMagickColorname method is:
3407 % MagickBooleanType QueryMagickColorname(const Image *image,
3408 % const PixelPacket *color,const ComplianceType compliance,char *name,
3409 % ExceptionInfo *exception)
3411 % A description of each parameter follows.
3413 % o image: the image.
3415 % o color: the color intensities.
3417 % o Compliance: Adhere to this color standard: SVG, X11, or XPM.
3419 % o name: Return the color name or hex value.
3421 % o exception: return any errors or warnings in this structure.
3424 MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
3425 const MagickPixelPacket *color,const ComplianceType compliance,
3426 char *name,ExceptionInfo *exception)
3434 register const ColorInfo
3439 if (compliance == XPMCompliance)
3441 pixel.matte=MagickFalse;
3442 pixel.depth=(unsigned long) MagickMin(1.0*image->depth,16.0);
3443 GetColorTuple(&pixel,MagickTrue,name);
3446 GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
3448 (void) GetColorInfo("*",exception);
3449 ResetLinkedListIterator(color_list);
3450 opacity=image->matte != MagickFalse ? color->opacity : OpaqueOpacity;
3451 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3452 while (p != (const ColorInfo *) NULL)
3454 if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
3455 (p->color.green == color->green) && (p->color.blue == color->blue) &&
3456 (p->color.opacity == opacity))
3458 (void) CopyMagickString(name,p->name,MaxTextExtent);
3461 p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
3467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3471 % U n i q u e I m a g e C o l o r s %
3475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3477 % UniqueImageColors() returns the unique colors of an image.
3479 % The format of the UniqueImageColors method is:
3481 % Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
3483 % A description of each parameter follows.
3485 % o image: the image.
3487 % o exception: return any errors or warnings in this structure.
3491 static void UniqueColorsToImage(Image *image,CubeInfo *cube_info,
3492 const NodeInfo *node_info,ExceptionInfo *exception)
3494 #define UniqueColorsImageTag "UniqueColors/Image"
3503 Traverse any children.
3505 number_children=image->matte == MagickFalse ? 8UL : 16UL;
3506 for (i=0; i < (long) number_children; i++)
3507 if (node_info->child[i] != (NodeInfo *) NULL)
3508 UniqueColorsToImage(image,cube_info,node_info->child[i],exception);
3509 if (node_info->level == (MaxTreeDepth-1))
3511 register ColorPacket
3514 register IndexPacket
3515 *__restrict indexes;
3517 register PixelPacket
3521 for (i=0; i < (long) node_info->number_unique; i++)
3523 q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception);
3524 if (q == (PixelPacket *) NULL)
3526 indexes=GetAuthenticIndexQueue(image);
3528 if (image->colorspace == CMYKColorspace)
3530 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3535 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
3536 (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse))
3537 (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress,
3538 cube_info->colors,image->client_data);
3539 cube_info->progress++;
3543 MagickExport Image *UniqueImageColors(const Image *image,
3544 ExceptionInfo *exception)
3552 cube_info=ClassifyImageColors(image,exception);
3553 if (cube_info == (CubeInfo *) NULL)
3554 return((Image *) NULL);
3555 unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
3556 if (unique_image == (Image *) NULL)
3557 return(unique_image);
3558 if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
3560 InheritException(exception,&unique_image->exception);
3561 unique_image=DestroyImage(unique_image);
3562 return((Image *) NULL);
3564 UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception);
3565 if (cube_info->colors < MaxColormapSize)
3570 quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
3571 quantize_info->number_colors=MaxColormapSize;
3572 quantize_info->dither=MagickFalse;
3573 quantize_info->tree_depth=8;
3574 (void) QuantizeImage(quantize_info,unique_image);
3575 quantize_info=DestroyQuantizeInfo(quantize_info);
3577 cube_info=DestroyCubeInfo(image,cube_info);
3578 return(unique_image);