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