MagickCore  6.9.13-23
Convert, Edit, Or Compose Bitmap Images
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 */
103 MagickExport 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 */
178 MagickExport MagickBooleanType CycleColormapImage(Image *image,
179  const ssize_t displace)
180 {
181  CacheView
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)
271 extern "C" {
272 #endif
273 
274 static 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 
293 MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
294 {
295  CacheView
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 }
Definition: image.h:134