MagickCore  7.1.1-43
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 "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 */
105 MagickExport 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 */
188 MagickExport MagickBooleanType CycleColormapImage(Image *image,
189  const ssize_t displace,ExceptionInfo *exception)
190 {
191  CacheView
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+=(ptrdiff_t) 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)
276 extern "C" {
277 #endif
278 
279 static 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 
299 MagickExport MagickBooleanType SortColormapByIntensity(Image *image,
300  ExceptionInfo *exception)
301 {
302  CacheView
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+=(ptrdiff_t) 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 }
_CacheView
Definition: cache-view.c:65
_Image
Definition: image.h:131
_PixelInfo
Definition: pixel.h:181
_ExceptionInfo
Definition: exception.h:101