1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % CCCC OOO L OOO RRRR M M AAA PPPP %
7 % C O O L O O R R MM MM A A P P %
8 % C O O L O O RRRR M M M AAAAA PPPP %
9 % C O O L O O R R M M A A P %
10 % CCCC OOO LLLLL OOO R R M M A A P %
11 % %
12 % %
13 % MagickCore Colormap Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % We use linked-lists because splay-trees do not currently support duplicate
37 % key / value pairs (.e.g X11 green compliance and SVG green compliance).
38 %
39 */
40
41 /*
42 Include declarations.
43 */
44 #include "MagickCore/studio.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colormap.h"
52 #include "MagickCore/client.h"
53 #include "MagickCore/configure.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/gem.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/option.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/quantize.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/resource_.h"
67 #include "MagickCore/semaphore.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/thread-private.h"
70 #include "MagickCore/token.h"
71 #include "MagickCore/utility.h"
72 #include "MagickCore/xml-tree.h"
73
74 /*
75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 % %
77 % %
78 % %
79 % A c q u i r e I m a g e C o l o r m a p %
80 % %
81 % %
82 % %
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 %
85 % AcquireImageColormap() allocates an image colormap and initializes
86 % it to a linear gray colorspace. If the image already has a colormap,
87 % it is replaced. AcquireImageColormap() returns MagickTrue if successful,
88 % otherwise MagickFalse if there is not enough memory.
89 %
90 % The format of the AcquireImageColormap method is:
91 %
92 % MagickBooleanType AcquireImageColormap(Image *image,const size_t colors,
93 % ExceptionInfo *exception)
94 %
95 % A description of each parameter follows:
96 %
97 % o image: the image.
98 %
99 % o colors: the number of colors in the image colormap.
100 %
101 % o exception: return any errors or warnings in this structure.
102 %
103 */
AcquireImageColormap(Image * image,const size_t colors,ExceptionInfo * exception)104 MagickExport MagickBooleanType AcquireImageColormap(Image *image,
105 const size_t colors,ExceptionInfo *exception)
106 {
107 register ssize_t
108 i;
109
110 /*
111 Allocate image colormap.
112 */
113 assert(image != (Image *) NULL);
114 assert(image->signature == MagickCoreSignature);
115 if (image->debug != MagickFalse)
116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
117 image->colors=MagickMax(colors,1);
118 if (image->colormap == (PixelInfo *) NULL)
119 image->colormap=(PixelInfo *) AcquireQuantumMemory(image->colors+1,
120 sizeof(*image->colormap));
121 else
122 image->colormap=(PixelInfo *) ResizeQuantumMemory(image->colormap,
123 image->colors+1,sizeof(*image->colormap));
124 if (image->colormap == (PixelInfo *) NULL)
125 {
126 image->colors=0;
127 image->storage_class=DirectClass;
128 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
129 image->filename);
130 }
131 for (i=0; i < (ssize_t) image->colors; i++)
132 {
133 double
134 pixel;
135
136 GetPixelInfo(image,image->colormap+i);
137 pixel=(double) (i*(QuantumRange/MagickMax(colors-1,1)));
138 image->colormap[i].red=pixel;
139 image->colormap[i].green=pixel;
140 image->colormap[i].blue=pixel;
141 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
142 image->colormap[i].alpha_trait=BlendPixelTrait;
143 }
144 return(SetImageStorageClass(image,PseudoClass,exception));
145 }
146
147 /*
148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 % %
150 % %
151 % %
152 % C y c l e C o l o r m a p I m a g e %
153 % %
154 % %
155 % %
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 %
158 % CycleColormap() displaces an image's colormap by a given number of
159 % positions. If you cycle the colormap a number of times you can produce
160 % a psychodelic effect.
161 %
162 % WARNING: this assumes an images colormap is in a well know and defined
163 % order. Currently Imagemagick has no way of setting that order.
164 %
165 % The format of the CycleColormapImage method is:
166 %
167 % MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace,
168 % ExceptionInfo *exception)
169 %
170 % A description of each parameter follows:
171 %
172 % o image: the image.
173 %
174 % o displace: displace the colormap this amount.
175 %
176 % o exception: return any errors or warnings in this structure.
177 %
178 */
CycleColormapImage(Image * image,const ssize_t displace,ExceptionInfo * exception)179 MagickExport MagickBooleanType CycleColormapImage(Image *image,
180 const ssize_t displace,ExceptionInfo *exception)
181 {
182 CacheView
183 *image_view;
184
185 MagickBooleanType
186 status;
187
188 ssize_t
189 y;
190
191 assert(image != (Image *) NULL);
192 assert(image->signature == MagickCoreSignature);
193 if (image->debug != MagickFalse)
194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
195 if (image->storage_class == DirectClass)
196 (void) SetImageType(image,PaletteType,exception);
197 status=MagickTrue;
198 image_view=AcquireAuthenticCacheView(image,exception);
199 #if defined(MAGICKCORE_OPENMP_SUPPORT)
200 #pragma omp parallel for schedule(static) \
201 magick_number_threads(image,image,image->rows,1)
202 #endif
203 for (y=0; y < (ssize_t) image->rows; y++)
204 {
205 register ssize_t
206 x;
207
208 register Quantum
209 *magick_restrict q;
210
211 ssize_t
212 index;
213
214 if (status == MagickFalse)
215 continue;
216 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
217 if (q == (Quantum *) NULL)
218 {
219 status=MagickFalse;
220 continue;
221 }
222 for (x=0; x < (ssize_t) image->columns; x++)
223 {
224 index=(ssize_t) (GetPixelIndex(image,q)+displace) % image->colors;
225 if (index < 0)
226 index+=(ssize_t) image->colors;
227 SetPixelIndex(image,(Quantum) index,q);
228 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
229 q+=GetPixelChannels(image);
230 }
231 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
232 status=MagickFalse;
233 }
234 image_view=DestroyCacheView(image_view);
235 return(status);
236 }
237
238 /*
239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 % %
241 % %
242 % %
243 + S o r t C o l o r m a p B y I n t e n s i t y %
244 % %
245 % %
246 % %
247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 %
249 % SortColormapByIntensity() sorts the colormap of a PseudoClass image by
250 % decreasing color intensity.
251 %
252 % The format of the SortColormapByIntensity method is:
253 %
254 % MagickBooleanType SortColormapByIntensity(Image *image,
255 % ExceptionInfo *exception)
256 %
257 % A description of each parameter follows:
258 %
259 % o image: A pointer to an Image structure.
260 %
261 % o exception: return any errors or warnings in this structure.
262 %
263 */
264
265 #if defined(__cplusplus) || defined(c_plusplus)
266 extern "C" {
267 #endif
268
IntensityCompare(const void * x,const void * y)269 static int IntensityCompare(const void *x,const void *y)
270 {
271 const PixelInfo
272 *color_1,
273 *color_2;
274
275 int
276 intensity;
277
278 color_1=(const PixelInfo *) x;
279 color_2=(const PixelInfo *) y;
280 intensity=(int) GetPixelInfoIntensity((const Image *) NULL,color_2)-(int)
281 GetPixelInfoIntensity((const Image *) NULL,color_1);
282 return(intensity);
283 }
284
285 #if defined(__cplusplus) || defined(c_plusplus)
286 }
287 #endif
288
SortColormapByIntensity(Image * image,ExceptionInfo * exception)289 MagickExport MagickBooleanType SortColormapByIntensity(Image *image,
290 ExceptionInfo *exception)
291 {
292 CacheView
293 *image_view;
294
295 MagickBooleanType
296 status;
297
298 register ssize_t
299 i;
300
301 ssize_t
302 y;
303
304 unsigned short
305 *pixels;
306
307 assert(image != (Image *) NULL);
308 if (image->debug != MagickFalse)
309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
310 assert(image->signature == MagickCoreSignature);
311 if (image->storage_class != PseudoClass)
312 return(MagickTrue);
313 /*
314 Allocate memory for pixel indexes.
315 */
316 pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors,
317 sizeof(*pixels));
318 if (pixels == (unsigned short *) NULL)
319 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
320 image->filename);
321 /*
322 Assign index values to colormap entries.
323 */
324 for (i=0; i < (ssize_t) image->colors; i++)
325 image->colormap[i].alpha=(double) i;
326 /*
327 Sort image colormap by decreasing color popularity.
328 */
329 qsort((void *) image->colormap,(size_t) image->colors,
330 sizeof(*image->colormap),IntensityCompare);
331 /*
332 Update image colormap indexes to sorted colormap order.
333 */
334 for (i=0; i < (ssize_t) image->colors; i++)
335 pixels[(ssize_t) image->colormap[i].alpha]=(unsigned short) i;
336 status=MagickTrue;
337 image_view=AcquireAuthenticCacheView(image,exception);
338 for (y=0; y < (ssize_t) image->rows; y++)
339 {
340 Quantum
341 index;
342
343 register ssize_t
344 x;
345
346 register Quantum
347 *magick_restrict q;
348
349 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
350 if (q == (Quantum *) NULL)
351 {
352 status=MagickFalse;
353 break;
354 }
355 for (x=0; x < (ssize_t) image->columns; x++)
356 {
357 index=(Quantum) pixels[(ssize_t) GetPixelIndex(image,q)];
358 SetPixelIndex(image,index,q);
359 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
360 q+=GetPixelChannels(image);
361 }
362 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
363 status=MagickFalse;
364 if (status == MagickFalse)
365 break;
366 }
367 image_view=DestroyCacheView(image_view);
368 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
369 return(status);
370 }
371