MagickCore 6.9.13
Loading...
Searching...
No Matches
colormap.c
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 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 "magick/studio.h"
45#include "magick/attribute.h"
46#include "magick/blob.h"
47#include "magick/cache-view.h"
48#include "magick/cache.h"
49#include "magick/color.h"
50#include "magick/color-private.h"
51#include "magick/colormap.h"
52#include "magick/colormap-private.h"
53#include "magick/client.h"
54#include "magick/configure.h"
55#include "magick/exception.h"
56#include "magick/exception-private.h"
57#include "magick/gem.h"
58#include "magick/geometry.h"
59#include "magick/image-private.h"
60#include "magick/memory_.h"
61#include "magick/monitor.h"
62#include "magick/monitor-private.h"
63#include "magick/option.h"
64#include "magick/pixel-accessor.h"
65#include "magick/pixel-private.h"
66#include "magick/quantize.h"
67#include "magick/quantum.h"
68#include "magick/semaphore.h"
69#include "magick/resource_.h"
70#include "magick/string_.h"
71#include "magick/thread-private.h"
72#include "magick/token.h"
73#include "magick/utility.h"
74#include "magick/xml-tree.h"
75
76/*
77%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78% %
79% %
80% %
81% A c q u i r e I m a g e C o l o r m a p %
82% %
83% %
84% %
85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86%
87% AcquireImageColormap() allocates an image colormap and initializes
88% it to a linear gray colorspace. If the image already has a colormap,
89% it is replaced. AcquireImageColormap() returns MagickTrue if successful,
90% otherwise MagickFalse if there is not enough memory.
91%
92% The format of the AcquireImageColormap method is:
93%
94% MagickBooleanType AcquireImageColormap(Image *image,const size_t colors)
95%
96% A description of each parameter follows:
97%
98% o image: the image.
99%
100% o colors: the number of colors in the image colormap.
101%
102*/
103MagickExport MagickBooleanType AcquireImageColormap(Image *image,
104 const size_t colors)
105{
106 ssize_t
107 i;
108
109 /*
110 Allocate image colormap.
111 */
112 assert(image != (Image *) NULL);
113 assert(image->signature == MagickCoreSignature);
114 if (IsEventLogging() != MagickFalse)
115 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
116 if (colors > MaxColormapSize)
117 {
118 image->colors=0;
119 image->storage_class=DirectClass;
120 ThrowBinaryImageException(ResourceLimitError,"UnableToCreateColormap",
121 image->filename);
122 }
123 image->colors=MagickMax(colors,1);
124 if (image->colormap == (PixelPacket *) NULL)
125 image->colormap=(PixelPacket *) AcquireQuantumMemory(image->colors+256,
126 sizeof(*image->colormap));
127 else
128 image->colormap=(PixelPacket *) ResizeQuantumMemory(image->colormap,
129 image->colors+256,sizeof(*image->colormap));
130 if (image->colormap == (PixelPacket *) NULL)
131 {
132 image->colors=0;
133 image->storage_class=DirectClass;
134 ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
135 image->filename);
136 }
137 for (i=0; i < (ssize_t) image->colors; i++)
138 {
139 size_t
140 pixel;
141
142 pixel=(size_t) (i*(QuantumRange/MagickMax(colors-1,1)));
143 image->colormap[i].red=(Quantum) pixel;
144 image->colormap[i].green=(Quantum) pixel;
145 image->colormap[i].blue=(Quantum) pixel;
146 image->colormap[i].opacity=OpaqueOpacity;
147 }
148 image->storage_class=PseudoClass;
149 return(MagickTrue);
150}
151
152/*
153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154% %
155% %
156% %
157% C y c l e C o l o r m a p I m a g e %
158% %
159% %
160% %
161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162%
163% CycleColormap() displaces an image's colormap by a given number of
164% positions. If you cycle the colormap a number of times you can produce
165% a psychodelic effect.
166%
167% The format of the CycleColormapImage method is:
168%
169% MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace)
170%
171% A description of each parameter follows:
172%
173% o image: the image.
174%
175% o displace: displace the colormap this amount.
176%
177*/
178MagickExport MagickBooleanType CycleColormapImage(Image *image,
179 const ssize_t displace)
180{
182 *image_view;
183
185 *exception;
186
187 MagickBooleanType
188 status;
189
190 ssize_t
191 y;
192
193 assert(image != (Image *) NULL);
194 assert(image->signature == MagickCoreSignature);
195 if (IsEventLogging() != MagickFalse)
196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
197 if (image->storage_class == DirectClass)
198 (void) SetImageType(image,PaletteType);
199 status=MagickTrue;
200 exception=(&image->exception);
201 image_view=AcquireAuthenticCacheView(image,exception);
202#if defined(MAGICKCORE_OPENMP_SUPPORT)
203 #pragma omp parallel for schedule(static) shared(status) \
204 magick_number_threads(image,image,image->rows,2)
205#endif
206 for (y=0; y < (ssize_t) image->rows; y++)
207 {
208 IndexPacket
209 *magick_restrict indexes;
210
211 ssize_t
212 x;
213
215 *magick_restrict q;
216
217 ssize_t
218 index;
219
220 if (status == MagickFalse)
221 continue;
222 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
223 if (q == (PixelPacket *) NULL)
224 {
225 status=MagickFalse;
226 continue;
227 }
228 indexes=GetCacheViewAuthenticIndexQueue(image_view);
229 for (x=0; x < (ssize_t) image->columns; x++)
230 {
231 index=(ssize_t) (GetPixelIndex(indexes+x)+displace) %
232 image->colors;
233 if (index < 0)
234 index+=(ssize_t) image->colors;
235 SetPixelIndex(indexes+x,index);
236 SetPixelRGBO(q,image->colormap+(ssize_t) index);
237 q++;
238 }
239 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
240 status=MagickFalse;
241 }
242 image_view=DestroyCacheView(image_view);
243 return(status);
244}
245
246/*
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248% %
249% %
250% %
251+ S o r t C o l o r m a p B y I n t e n s i t y %
252% %
253% %
254% %
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256%
257% SortColormapByIntensity() sorts the colormap of a PseudoClass image by
258% decreasing color intensity.
259%
260% The format of the SortColormapByIntensity method is:
261%
262% MagickBooleanType SortColormapByIntensity(Image *image)
263%
264% A description of each parameter follows:
265%
266% o image: A pointer to an Image structure.
267%
268*/
269
270#if defined(__cplusplus) || defined(c_plusplus)
271extern "C" {
272#endif
273
274static int IntensityCompare(const void *x,const void *y)
275{
276 const PixelPacket
277 *color_1,
278 *color_2;
279
280 int
281 intensity;
282
283 color_1=(const PixelPacket *) x;
284 color_2=(const PixelPacket *) y;
285 intensity=PixelPacketIntensity(color_2)-(int) PixelPacketIntensity(color_1);
286 return(intensity);
287}
288
289#if defined(__cplusplus) || defined(c_plusplus)
290}
291#endif
292
293MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
294{
296 *image_view;
297
299 *exception;
300
301 MagickBooleanType
302 status;
303
304 ssize_t
305 i,
306 y;
307
308 unsigned short
309 *pixels;
310
311 assert(image != (Image *) NULL);
312 assert(image->signature == MagickCoreSignature);
313 if (IsEventLogging() != MagickFalse)
314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
315 if (image->storage_class != PseudoClass)
316 return(MagickTrue);
317 exception=(&image->exception);
318 /*
319 Allocate memory for pixel indexes.
320 */
321 pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors,
322 sizeof(*pixels));
323 if (pixels == (unsigned short *) NULL)
324 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
325 image->filename);
326 /*
327 Assign index values to colormap entries.
328 */
329 for (i=0; i < (ssize_t) image->colors; i++)
330 image->colormap[i].opacity=(IndexPacket) i;
331 /*
332 Sort image colormap by decreasing color popularity.
333 */
334 qsort((void *) image->colormap,(size_t) image->colors,
335 sizeof(*image->colormap),IntensityCompare);
336 /*
337 Update image colormap indexes to sorted colormap order.
338 */
339 for (i=0; i < (ssize_t) image->colors; i++)
340 pixels[(ssize_t) image->colormap[i].opacity]=(unsigned short) i;
341 status=MagickTrue;
342 image_view=AcquireAuthenticCacheView(image,exception);
343#if defined(MAGICKCORE_OPENMP_SUPPORT)
344 #pragma omp parallel for schedule(static) shared(status) \
345 magick_number_threads(image,image,image->rows,2)
346#endif
347 for (y=0; y < (ssize_t) image->rows; y++)
348 {
349 IndexPacket
350 *magick_restrict indexes;
351
353 *magick_restrict q;
354
355 ssize_t
356 x;
357
358 if (status == MagickFalse)
359 continue;
360 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
361 if (q == (PixelPacket *) NULL)
362 {
363 status=MagickFalse;
364 continue;
365 }
366 indexes=GetCacheViewAuthenticIndexQueue(image_view);
367 for (x=0; x < (ssize_t) image->columns; x++)
368 {
369 IndexPacket
370 index;
371
372 ssize_t
373 i;
374
375 i=ConstrainColormapIndex(image,GetPixelIndex(indexes+x));
376 index=(IndexPacket) pixels[i];
377 SetPixelIndex(indexes+x,index);
378 SetPixelRGBO(q,image->colormap+(ssize_t) index);
379 q++;
380 }
381 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
382 status=MagickFalse;
383 }
384 image_view=DestroyCacheView(image_view);
385 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
386 return(status);
387}