MagickCore  6.9.13-46
Convert, Edit, Or Compose Bitmap Images
quantize.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % QQQ U U AAA N N TTTTT IIIII ZZZZZ EEEEE %
7 % Q Q U U A A NN N T I ZZ E %
8 % Q Q U U AAAAA N N N T I ZZZ EEEEE %
9 % Q QQ U U A A N NN T I ZZ E %
10 % QQQQ UUU A A N N T IIIII ZZZZZ EEEEE %
11 % %
12 % %
13 % MagickCore Methods to Reduce the Number of Unique Colors in an Image %
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/license/ %
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 % Realism in computer graphics typically requires using 24 bits/pixel to
37 % generate an image. Yet many graphic display devices do not contain the
38 % amount of memory necessary to match the spatial and color resolution of
39 % the human eye. The Quantize methods takes a 24 bit image and reduces
40 % the number of colors so it can be displayed on raster device with less
41 % bits per pixel. In most instances, the quantized image closely
42 % resembles the original reference image.
43 %
44 % A reduction of colors in an image is also desirable for image
45 % transmission and real-time animation.
46 %
47 % QuantizeImage() takes a standard RGB or monochrome images and quantizes
48 % them down to some fixed number of colors.
49 %
50 % For purposes of color allocation, an image is a set of n pixels, where
51 % each pixel is a point in RGB space. RGB space is a 3-dimensional
52 % vector space, and each pixel, Pi, is defined by an ordered triple of
53 % red, green, and blue coordinates, (Ri, Gi, Bi).
54 %
55 % Each primary color component (red, green, or blue) represents an
56 % intensity which varies linearly from 0 to a maximum value, Cmax, which
57 % corresponds to full saturation of that color. Color allocation is
58 % defined over a domain consisting of the cube in RGB space with opposite
59 % vertices at (0,0,0) and (Cmax, Cmax, Cmax). QUANTIZE requires Cmax =
60 % 255.
61 %
62 % The algorithm maps this domain onto a tree in which each node
63 % represents a cube within that domain. In the following discussion
64 % these cubes are defined by the coordinate of two opposite vertices (vertex
65 % nearest the origin in RGB space and the vertex farthest from the origin).
66 %
67 % The tree's root node represents the entire domain, (0,0,0) through
68 % (Cmax,Cmax,Cmax). Each lower level in the tree is generated by
69 % subdividing one node's cube into eight smaller cubes of equal size.
70 % This corresponds to bisecting the parent cube with planes passing
71 % through the midpoints of each edge.
72 %
73 % The basic algorithm operates in three phases: Classification,
74 % Reduction, and Assignment. Classification builds a color description
75 % tree for the image. Reduction collapses the tree until the number it
76 % represents, at most, the number of colors desired in the output image.
77 % Assignment defines the output image's color map and sets each pixel's
78 % color by restorage_class in the reduced tree. Our goal is to minimize
79 % the numerical discrepancies between the original colors and quantized
80 % colors (quantization error).
81 %
82 % Classification begins by initializing a color description tree of
83 % sufficient depth to represent each possible input color in a leaf.
84 % However, it is impractical to generate a fully-formed color description
85 % tree in the storage_class phase for realistic values of Cmax. If
86 % colors components in the input image are quantized to k-bit precision,
87 % so that Cmax= 2k-1, the tree would need k levels below the root node to
88 % allow representing each possible input color in a leaf. This becomes
89 % prohibitive because the tree's total number of nodes is 1 +
90 % sum(i=1, k, 8k).
91 %
92 % A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
93 % Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
94 % Initializes data structures for nodes only as they are needed; (2)
95 % Chooses a maximum depth for the tree as a function of the desired
96 % number of colors in the output image (currently log2(colormap size)).
97 %
98 % For each pixel in the input image, storage_class scans downward from
99 % the root of the color description tree. At each level of the tree it
100 % identifies the single node which represents a cube in RGB space
101 % containing the pixel's color. It updates the following data for each
102 % such node:
103 %
104 % n1: Number of pixels whose color is contained in the RGB cube which
105 % this node represents;
106 %
107 % n2: Number of pixels whose color is not represented in a node at
108 % lower depth in the tree; initially, n2 = 0 for all nodes except
109 % leaves of the tree.
110 %
111 % Sr, Sg, Sb: Sums of the red, green, and blue component values for all
112 % pixels not classified at a lower depth. The combination of these sums
113 % and n2 will ultimately characterize the mean color of a set of pixels
114 % represented by this node.
115 %
116 % E: the distance squared in RGB space between each pixel contained
117 % within a node and the nodes' center. This represents the
118 % quantization error for a node.
119 %
120 % Reduction repeatedly prunes the tree until the number of nodes with n2
121 % > 0 is less than or equal to the maximum number of colors allowed in
122 % the output image. On any given iteration over the tree, it selects
123 % those nodes whose E count is minimal for pruning and merges their color
124 % statistics upward. It uses a pruning threshold, Ep, to govern node
125 % selection as follows:
126 %
127 % Ep = 0
128 % while number of nodes with (n2 > 0) > required maximum number of colors
129 % prune all nodes such that E <= Ep
130 % Set Ep to minimum E in remaining nodes
131 %
132 % This has the effect of minimizing any quantization error when merging
133 % two nodes together.
134 %
135 % When a node to be pruned has offspring, the pruning procedure invokes
136 % itself recursively in order to prune the tree from the leaves upward.
137 % n2, Sr, Sg, and Sb in a node being pruned are always added to the
138 % corresponding data in that node's parent. This retains the pruned
139 % node's color characteristics for later averaging.
140 %
141 % For each node, n2 pixels exist for which that node represents the
142 % smallest volume in RGB space containing those pixel's colors. When n2
143 % > 0 the node will uniquely define a color in the output image. At the
144 % beginning of reduction, n2 = 0 for all nodes except a the leaves of
145 % the tree which represent colors present in the input image.
146 %
147 % The other pixel count, n1, indicates the total number of colors within
148 % the cubic volume which the node represents. This includes n1 - n2
149 % pixels whose colors should be defined by nodes at a lower level in the
150 % tree.
151 %
152 % Assignment generates the output image from the pruned tree. The output
153 % image consists of two parts: (1) A color map, which is an array of
154 % color descriptions (RGB triples) for each color present in the output
155 % image; (2) A pixel array, which represents each pixel as an index
156 % into the color map array.
157 %
158 % First, the assignment phase makes one pass over the pruned color
159 % description tree to establish the image's color map. For each node
160 % with n2 > 0, it divides Sr, Sg, and Sb by n2 . This produces the mean
161 % color of all pixels that classify no lower than this node. Each of
162 % these colors becomes an entry in the color map.
163 %
164 % Finally, the assignment phase reclassifies each pixel in the pruned
165 % tree to identify the deepest node containing the pixel's color. The
166 % pixel's value in the pixel array becomes the index of this node's mean
167 % color in the color map.
168 %
169 % This method is based on a similar algorithm written by Paul Raveling.
170 %
171 */
172 
173 /*
174  Include declarations.
175 */
176 #include "magick/studio.h"
177 #include "magick/artifact.h"
178 #include "magick/attribute.h"
179 #include "magick/cache-view.h"
180 #include "magick/color.h"
181 #include "magick/color-private.h"
182 #include "magick/colormap.h"
183 #include "magick/colorspace.h"
184 #include "magick/colorspace-private.h"
185 #include "magick/enhance.h"
186 #include "magick/exception.h"
187 #include "magick/exception-private.h"
188 #include "magick/histogram.h"
189 #include "magick/image.h"
190 #include "magick/image-private.h"
191 #include "magick/list.h"
192 #include "magick/memory_.h"
193 #include "magick/monitor.h"
194 #include "magick/monitor-private.h"
195 #include "magick/option.h"
196 #include "magick/pixel-private.h"
197 #include "magick/quantize.h"
198 #include "magick/quantum.h"
199 #include "magick/resource_.h"
200 #include "magick/string_.h"
201 #include "magick/string-private.h"
202 #include "magick/thread-private.h"
203 
204 /*
205  Define declarations.
206 */
207 #if !defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
208 #define CacheShift 2
209 #else
210 #define CacheShift 3
211 #endif
212 #define ErrorQueueLength 16
213 #define ErrorRelativeWeight MagickSafeReciprocal(16)
214 #define MaxQNodes 266817
215 #define MaxTreeDepth 8
216 #define QNodesInAList 1920
217 
218 /*
219  Typedef declarations.
220 */
221 typedef struct _QNodeInfo
222 {
223  struct _QNodeInfo
224  *parent,
225  *child[16];
226 
227  MagickSizeType
228  number_unique;
229 
231  total_color;
232 
233  MagickRealType
234  quantize_error;
235 
236  size_t
237  color_number,
238  id,
239  level;
240 } QNodeInfo;
241 
242 typedef struct _QNodes
243 {
244  QNodeInfo
245  *nodes;
246 
247  struct _QNodes
248  *next;
249 } QNodes;
250 
251 typedef struct _QCubeInfo
252 {
253  QNodeInfo
254  *root;
255 
256  size_t
257  colors,
258  maximum_colors;
259 
260  ssize_t
261  transparent_index;
262 
263  MagickSizeType
264  transparent_pixels;
265 
267  target;
268 
269  MagickRealType
270  distance,
271  pruning_threshold,
272  next_threshold;
273 
274  size_t
275  nodes,
276  free_nodes,
277  color_number;
278 
279  QNodeInfo
280  *next_node;
281 
282  QNodes
283  *node_queue;
284 
285  MemoryInfo
286  *memory_info;
287 
288  ssize_t
289  *cache;
290 
292  error[ErrorQueueLength];
293 
294  MagickRealType
295  diffusion,
296  weights[ErrorQueueLength];
297 
299  *quantize_info;
300 
301  MagickBooleanType
302  associate_alpha;
303 
304  ssize_t
305  x,
306  y;
307 
308  size_t
309  depth;
310 
311  MagickOffsetType
312  offset;
313 
314  MagickSizeType
315  span;
316 } QCubeInfo;
317 
318 /*
319  Method prototypes.
320 */
321 static QCubeInfo
322  *GetQCubeInfo(const QuantizeInfo *,const size_t,const size_t);
323 
324 static QNodeInfo
325  *GetQNodeInfo(QCubeInfo *,const size_t,const size_t,QNodeInfo *);
326 
327 static MagickBooleanType
328  AssignImageColors(Image *,QCubeInfo *),
329  ClassifyImageColors(QCubeInfo *,const Image *,ExceptionInfo *),
330  DitherImage(Image *,QCubeInfo *),
331  SetGrayscaleImage(Image *);
332 
333 static void
334  ClosestColor(const Image *,QCubeInfo *,const QNodeInfo *),
335  DefineImageColormap(Image *,QCubeInfo *,QNodeInfo *),
336  DestroyQCubeInfo(QCubeInfo *),
337  PruneLevel(QCubeInfo *,const QNodeInfo *),
338  PruneToCubeDepth(QCubeInfo *,const QNodeInfo *),
339  ReduceImageColors(const Image *,QCubeInfo *);
340 
341 /*
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 % %
344 % %
345 % %
346 % A c q u i r e Q u a n t i z e I n f o %
347 % %
348 % %
349 % %
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 %
352 % AcquireQuantizeInfo() allocates the QuantizeInfo structure.
353 %
354 % The format of the AcquireQuantizeInfo method is:
355 %
356 % QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
357 %
358 % A description of each parameter follows:
359 %
360 % o image_info: the image info.
361 %
362 */
363 MagickExport QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
364 {
366  *quantize_info;
367 
368  quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
369  if (quantize_info == (QuantizeInfo *) NULL)
370  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
371  GetQuantizeInfo(quantize_info);
372  if (image_info != (ImageInfo *) NULL)
373  {
374  const char
375  *option;
376 
377  quantize_info->dither=image_info->dither;
378  option=GetImageOption(image_info,"dither");
379  if (option != (const char *) NULL)
380  quantize_info->dither_method=(DitherMethod) ParseCommandOption(
381  MagickDitherOptions,MagickFalse,option);
382  quantize_info->measure_error=image_info->verbose;
383  }
384  return(quantize_info);
385 }
386 
387 /*
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389 % %
390 % %
391 % %
392 + A s s i g n I m a g e C o l o r s %
393 % %
394 % %
395 % %
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 %
398 % AssignImageColors() generates the output image from the pruned tree. The
399 % output image consists of two parts: (1) A color map, which is an array
400 % of color descriptions (RGB triples) for each color present in the
401 % output image; (2) A pixel array, which represents each pixel as an
402 % index into the color map array.
403 %
404 % First, the assignment phase makes one pass over the pruned color
405 % description tree to establish the image's color map. For each node
406 % with n2 > 0, it divides Sr, Sg, and Sb by n2 . This produces the mean
407 % color of all pixels that classify no lower than this node. Each of
408 % these colors becomes an entry in the color map.
409 %
410 % Finally, the assignment phase reclassifies each pixel in the pruned
411 % tree to identify the deepest node containing the pixel's color. The
412 % pixel's value in the pixel array becomes the index of this node's mean
413 % color in the color map.
414 %
415 % The format of the AssignImageColors() method is:
416 %
417 % MagickBooleanType AssignImageColors(Image *image,QCubeInfo *cube_info)
418 %
419 % A description of each parameter follows.
420 %
421 % o image: the image.
422 %
423 % o cube_info: A pointer to the Cube structure.
424 %
425 */
426 
427 static inline void AssociateAlphaPixel(const QCubeInfo *cube_info,
428  const PixelPacket *pixel,DoublePixelPacket *alpha_pixel)
429 {
430  MagickRealType
431  alpha;
432 
433  alpha_pixel->index=0;
434  if ((cube_info->associate_alpha == MagickFalse) ||
435  (pixel->opacity == OpaqueOpacity))
436  {
437  alpha_pixel->red=(MagickRealType) GetPixelRed(pixel);
438  alpha_pixel->green=(MagickRealType) GetPixelGreen(pixel);
439  alpha_pixel->blue=(MagickRealType) GetPixelBlue(pixel);
440  alpha_pixel->opacity=(MagickRealType) GetPixelOpacity(pixel);
441  return;
442  }
443  alpha=(MagickRealType) (QuantumScale*((MagickRealType) QuantumRange-
444  (MagickRealType) GetPixelOpacity(pixel)));
445  alpha_pixel->red=alpha*(MagickRealType) GetPixelRed(pixel);
446  alpha_pixel->green=alpha*(MagickRealType) GetPixelGreen(pixel);
447  alpha_pixel->blue=alpha*(MagickRealType) GetPixelBlue(pixel);
448  alpha_pixel->opacity=(MagickRealType) GetPixelOpacity(pixel);
449 }
450 
451 static inline size_t ColorToQNodeId(const QCubeInfo *cube_info,
452  const DoublePixelPacket *pixel,size_t index)
453 {
454  size_t
455  id;
456 
457  id=(size_t) (((ScaleQuantumToChar(ClampPixel(GetPixelRed(pixel))) >> index) &
458  0x01) | ((ScaleQuantumToChar(ClampPixel(GetPixelGreen(pixel))) >> index) &
459  0x01) << 1 | ((ScaleQuantumToChar(ClampPixel(GetPixelBlue(pixel))) >>
460  index) & 0x01) << 2);
461  if (cube_info->associate_alpha != MagickFalse)
462  id|=((ScaleQuantumToChar(ClampPixel(GetPixelOpacity(pixel))) >> index) &
463  0x1) << 3;
464  return(id);
465 }
466 
467 static inline MagickBooleanType IsSameColor(const Image *image,
468  const PixelPacket *p,const PixelPacket *q)
469 {
470  if ((GetPixelRed(p) != GetPixelRed(q)) ||
471  (GetPixelGreen(p) != GetPixelGreen(q)) ||
472  (GetPixelBlue(p) != GetPixelBlue(q)))
473  return(MagickFalse);
474  if ((image->matte != MagickFalse) &&
475  (GetPixelOpacity(p) != GetPixelOpacity(q)))
476  return(MagickFalse);
477  return(MagickTrue);
478 }
479 
480 static MagickBooleanType AssignImageColors(Image *image,QCubeInfo *cube_info)
481 {
482 #define AssignImageTag "Assign/Image"
483 
484  ColorspaceType
485  colorspace;
486 
487  size_t
488  number_colors;
489 
490  ssize_t
491  y;
492 
493  /*
494  Allocate image colormap.
495  */
496  colorspace=image->colorspace;
497  if (cube_info->quantize_info->colorspace != UndefinedColorspace)
498  (void) TransformImageColorspace(image,cube_info->quantize_info->colorspace);
499  number_colors=MagickMax(cube_info->colors,cube_info->maximum_colors);
500  if (AcquireImageColormap(image,number_colors) == MagickFalse)
501  ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
502  image->filename);
503  image->colors=0;
504  cube_info->transparent_pixels=0;
505  cube_info->transparent_index=(-1);
506  DefineImageColormap(image,cube_info,cube_info->root);
507  /*
508  Create a reduced color image.
509  */
510  if ((cube_info->quantize_info->dither != MagickFalse) &&
511  (cube_info->quantize_info->dither_method != NoDitherMethod))
512  (void) DitherImage(image,cube_info);
513  else
514  {
515  CacheView
516  *image_view;
517 
519  *exception;
520 
521  MagickBooleanType
522  status;
523 
524  status=MagickTrue;
525  exception=(&image->exception);
526  image_view=AcquireAuthenticCacheView(image,exception);
527 #if defined(MAGICKCORE_OPENMP_SUPPORT)
528  #pragma omp parallel for schedule(static) shared(status) \
529  magick_number_threads(image,image,image->rows,1)
530 #endif
531  for (y=0; y < (ssize_t) image->rows; y++)
532  {
533  IndexPacket
534  *magick_restrict indexes;
535 
537  *magick_restrict q;
538 
539  QCubeInfo
540  cube;
541 
542  ssize_t
543  x;
544 
545  ssize_t
546  count;
547 
548  if (status == MagickFalse)
549  continue;
550  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
551  exception);
552  if (q == (PixelPacket *) NULL)
553  {
554  status=MagickFalse;
555  continue;
556  }
557  indexes=GetCacheViewAuthenticIndexQueue(image_view);
558  cube=(*cube_info);
559  for (x=0; x < (ssize_t) image->columns; x+=count)
560  {
562  pixel;
563 
564  const QNodeInfo
565  *node_info;
566 
567  ssize_t
568  i;
569 
570  size_t
571  id,
572  index;
573 
574  /*
575  Identify the deepest node containing the pixel's color.
576  */
577  for (count=1; (x+count) < (ssize_t) image->columns; count++)
578  if (IsSameColor(image,q,q+count) == MagickFalse)
579  break;
580  AssociateAlphaPixel(&cube,q,&pixel);
581  node_info=cube.root;
582  for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
583  {
584  id=ColorToQNodeId(&cube,&pixel,index);
585  if (node_info->child[id] == (QNodeInfo *) NULL)
586  break;
587  node_info=node_info->child[id];
588  }
589  /*
590  Find closest color among siblings and their children.
591  */
592  cube.target=pixel;
593  cube.distance=(MagickRealType) (4.0*((MagickRealType) QuantumRange+
594  1.0)*((MagickRealType) QuantumRange+1.0)+1.0);
595  ClosestColor(image,&cube,node_info->parent);
596  index=cube.color_number;
597  for (i=0; i < (ssize_t) count; i++)
598  {
599  if (image->storage_class == PseudoClass)
600  SetPixelIndex(indexes+x+i,index);
601  if (cube.quantize_info->measure_error == MagickFalse)
602  {
603  SetPixelRgb(q,image->colormap+index);
604  if (cube.associate_alpha != MagickFalse)
605  SetPixelOpacity(q,image->colormap[index].opacity);
606  }
607  q++;
608  }
609  }
610  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
611  status=MagickFalse;
612  if (image->progress_monitor != (MagickProgressMonitor) NULL)
613  {
614  MagickBooleanType
615  proceed;
616 
617  proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
618  image->rows);
619  if (proceed == MagickFalse)
620  status=MagickFalse;
621  }
622  }
623  image_view=DestroyCacheView(image_view);
624  }
625  if (cube_info->quantize_info->measure_error != MagickFalse)
626  (void) GetImageQuantizeError(image);
627  if ((cube_info->quantize_info->number_colors == 2) &&
628  (IsGrayColorspace(cube_info->quantize_info->colorspace)))
629  {
630  double
631  intensity;
632 
633  /*
634  Monochrome image.
635  */
636  intensity=GetPixelLuma(image,image->colormap+0) <
637  (MagickRealType) QuantumRange/2.0 ? 0.0 : (double) QuantumRange;
638  if ((image->colors > 1) &&
639  (GetPixelLuma(image,image->colormap+0) >
640  GetPixelLuma(image,image->colormap+1)))
641  intensity=(double) QuantumRange;
642  image->colormap[0].red=intensity;
643  image->colormap[0].green=intensity;
644  image->colormap[0].blue=intensity;
645  if (image->colors > 1)
646  {
647  image->colormap[1].red=(double) QuantumRange-intensity;
648  image->colormap[1].green=(double) QuantumRange-intensity;
649  image->colormap[1].blue=(double) QuantumRange-intensity;
650  }
651  }
652  (void) SyncImage(image);
653  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
654  (IssRGBCompatibleColorspace(colorspace) == MagickFalse))
655  (void) TransformImageColorspace(image,colorspace);
656  return(MagickTrue);
657 }
658 
659 /*
660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661 % %
662 % %
663 % %
664 + C l a s s i f y I m a g e C o l o r s %
665 % %
666 % %
667 % %
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 %
670 % ClassifyImageColors() begins by initializing a color description tree
671 % of sufficient depth to represent each possible input color in a leaf.
672 % However, it is impractical to generate a fully-formed color
673 % description tree in the storage_class phase for realistic values of
674 % Cmax. If colors components in the input image are quantized to k-bit
675 % precision, so that Cmax= 2k-1, the tree would need k levels below the
676 % root node to allow representing each possible input color in a leaf.
677 % This becomes prohibitive because the tree's total number of nodes is
678 % 1 + sum(i=1,k,8k).
679 %
680 % A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
681 % Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
682 % Initializes data structures for nodes only as they are needed; (2)
683 % Chooses a maximum depth for the tree as a function of the desired
684 % number of colors in the output image (currently log2(colormap size)).
685 %
686 % For each pixel in the input image, storage_class scans downward from
687 % the root of the color description tree. At each level of the tree it
688 % identifies the single node which represents a cube in RGB space
689 % containing It updates the following data for each such node:
690 %
691 % n1 : Number of pixels whose color is contained in the RGB cube
692 % which this node represents;
693 %
694 % n2 : Number of pixels whose color is not represented in a node at
695 % lower depth in the tree; initially, n2 = 0 for all nodes except
696 % leaves of the tree.
697 %
698 % Sr, Sg, Sb : Sums of the red, green, and blue component values for
699 % all pixels not classified at a lower depth. The combination of
700 % these sums and n2 will ultimately characterize the mean color of a
701 % set of pixels represented by this node.
702 %
703 % E: the distance squared in RGB space between each pixel contained
704 % within a node and the nodes' center. This represents the quantization
705 % error for a node.
706 %
707 % The format of the ClassifyImageColors() method is:
708 %
709 % MagickBooleanType ClassifyImageColors(QCubeInfo *cube_info,
710 % const Image *image,ExceptionInfo *exception)
711 %
712 % A description of each parameter follows.
713 %
714 % o cube_info: A pointer to the Cube structure.
715 %
716 % o image: the image.
717 %
718 */
719 
720 static inline void SetAssociatedAlpha(const Image *image,QCubeInfo *cube_info)
721 {
722  MagickBooleanType
723  associate_alpha;
724 
725  associate_alpha=image->matte;
726  if ((cube_info->quantize_info->number_colors == 2) &&
727  ((cube_info->quantize_info->colorspace == LinearGRAYColorspace) ||
728  (cube_info->quantize_info->colorspace == GRAYColorspace)))
729  associate_alpha=MagickFalse;
730  cube_info->associate_alpha=associate_alpha;
731 }
732 
733 static MagickBooleanType ClassifyImageColors(QCubeInfo *cube_info,
734  const Image *image,ExceptionInfo *exception)
735 {
736 #define ClassifyImageTag "Classify/Image"
737 
738  CacheView
739  *image_view;
740 
742  error,
743  mid,
744  midpoint,
745  pixel;
746 
747  MagickBooleanType
748  proceed;
749 
750  MagickRealType
751  bisect;
752 
753  QNodeInfo
754  *node_info;
755 
756  size_t
757  count,
758  id,
759  index,
760  level;
761 
762  ssize_t
763  y;
764 
765  /*
766  Classify the first cube_info->maximum_colors colors to a tree depth of 8.
767  */
768  SetAssociatedAlpha(image,cube_info);
769  if (cube_info->quantize_info->colorspace != image->colorspace)
770  {
771  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
772  (cube_info->quantize_info->colorspace != CMYKColorspace))
773  (void) TransformImageColorspace((Image *) image,
774  cube_info->quantize_info->colorspace);
775  else
776  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
777  (void) TransformImageColorspace((Image *) image,sRGBColorspace);
778  }
779  midpoint.red=(MagickRealType) QuantumRange/2.0;
780  midpoint.green=(MagickRealType) QuantumRange/2.0;
781  midpoint.blue=(MagickRealType) QuantumRange/2.0;
782  midpoint.opacity=(MagickRealType) QuantumRange/2.0;
783  midpoint.index=(MagickRealType) QuantumRange/2.0;
784  error.opacity=0.0;
785  image_view=AcquireVirtualCacheView(image,exception);
786  for (y=0; y < (ssize_t) image->rows; y++)
787  {
788  const PixelPacket
789  *magick_restrict p;
790 
791  ssize_t
792  x;
793 
794  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
795  if (p == (const PixelPacket *) NULL)
796  break;
797  if (cube_info->nodes > MaxQNodes)
798  {
799  /*
800  Prune one level if the color tree is too large.
801  */
802  PruneLevel(cube_info,cube_info->root);
803  cube_info->depth--;
804  }
805  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
806  {
807  /*
808  Start at the root and descend the color cube tree.
809  */
810  for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
811  if (IsSameColor(image,p,p+count) == MagickFalse)
812  break;
813  AssociateAlphaPixel(cube_info,p,&pixel);
814  index=MaxTreeDepth-1;
815  bisect=((MagickRealType) QuantumRange+1.0)/2.0;
816  mid=midpoint;
817  node_info=cube_info->root;
818  for (level=1; level <= MaxTreeDepth; level++)
819  {
820  double
821  distance;
822 
823  bisect*=0.5;
824  id=ColorToQNodeId(cube_info,&pixel,index);
825  mid.red+=(id & 1) != 0 ? bisect : -bisect;
826  mid.green+=(id & 2) != 0 ? bisect : -bisect;
827  mid.blue+=(id & 4) != 0 ? bisect : -bisect;
828  mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
829  if (node_info->child[id] == (QNodeInfo *) NULL)
830  {
831  /*
832  Set colors of new node to contain pixel.
833  */
834  node_info->child[id]=GetQNodeInfo(cube_info,id,level,node_info);
835  if (node_info->child[id] == (QNodeInfo *) NULL)
836  {
837  (void) ThrowMagickException(exception,GetMagickModule(),
838  ResourceLimitError,"MemoryAllocationFailed","`%s'",
839  image->filename);
840  continue;
841  }
842  if (level == MaxTreeDepth)
843  cube_info->colors++;
844  }
845  /*
846  Approximate the quantization error represented by this node.
847  */
848  node_info=node_info->child[id];
849  error.red=QuantumScale*(pixel.red-mid.red);
850  error.green=QuantumScale*(pixel.green-mid.green);
851  error.blue=QuantumScale*(pixel.blue-mid.blue);
852  if (cube_info->associate_alpha != MagickFalse)
853  error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
854  distance=(double) (error.red*error.red+error.green*error.green+
855  error.blue*error.blue+error.opacity*error.opacity);
856  if (IsNaN(distance) != 0)
857  distance=0.0;
858  node_info->quantize_error+=count*sqrt(distance);
859  cube_info->root->quantize_error+=node_info->quantize_error;
860  index--;
861  }
862  /*
863  Sum RGB for this leaf for later derivation of the mean cube color.
864  */
865  node_info->number_unique+=count;
866  node_info->total_color.red+=count*QuantumScale*(MagickRealType)
867  ClampPixel(pixel.red);
868  node_info->total_color.green+=count*QuantumScale*(MagickRealType)
869  ClampPixel(pixel.green);
870  node_info->total_color.blue+=count*QuantumScale*(MagickRealType)
871  ClampPixel(pixel.blue);
872  if (cube_info->associate_alpha != MagickFalse)
873  node_info->total_color.opacity+=count*QuantumScale*(MagickRealType)
874  ClampPixel(pixel.opacity);
875  else
876  node_info->total_color.opacity+=count*QuantumScale*(MagickRealType)
877  ClampPixel(OpaqueOpacity);
878  p+=(ptrdiff_t) count;
879  }
880  if (cube_info->colors > cube_info->maximum_colors)
881  {
882  PruneToCubeDepth(cube_info,cube_info->root);
883  break;
884  }
885  proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
886  image->rows);
887  if (proceed == MagickFalse)
888  break;
889  }
890  for (y++; y < (ssize_t) image->rows; y++)
891  {
892  const PixelPacket
893  *magick_restrict p;
894 
895  ssize_t
896  x;
897 
898  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
899  if (p == (const PixelPacket *) NULL)
900  break;
901  if (cube_info->nodes > MaxQNodes)
902  {
903  /*
904  Prune one level if the color tree is too large.
905  */
906  PruneLevel(cube_info,cube_info->root);
907  cube_info->depth--;
908  }
909  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
910  {
911  /*
912  Start at the root and descend the color cube tree.
913  */
914  for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
915  if (IsSameColor(image,p,p+count) == MagickFalse)
916  break;
917  AssociateAlphaPixel(cube_info,p,&pixel);
918  index=MaxTreeDepth-1;
919  bisect=((MagickRealType) QuantumRange+1.0)/2.0;
920  mid=midpoint;
921  node_info=cube_info->root;
922  for (level=1; level <= cube_info->depth; level++)
923  {
924  double
925  distance;
926 
927  bisect*=0.5;
928  id=ColorToQNodeId(cube_info,&pixel,index);
929  mid.red+=(id & 1) != 0 ? bisect : -bisect;
930  mid.green+=(id & 2) != 0 ? bisect : -bisect;
931  mid.blue+=(id & 4) != 0 ? bisect : -bisect;
932  mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
933  if (node_info->child[id] == (QNodeInfo *) NULL)
934  {
935  /*
936  Set colors of new node to contain pixel.
937  */
938  node_info->child[id]=GetQNodeInfo(cube_info,id,level,node_info);
939  if (node_info->child[id] == (QNodeInfo *) NULL)
940  {
941  (void) ThrowMagickException(exception,GetMagickModule(),
942  ResourceLimitError,"MemoryAllocationFailed","%s",
943  image->filename);
944  continue;
945  }
946  if (level == cube_info->depth)
947  cube_info->colors++;
948  }
949  /*
950  Approximate the quantization error represented by this node.
951  */
952  node_info=node_info->child[id];
953  error.red=QuantumScale*(pixel.red-mid.red);
954  error.green=QuantumScale*(pixel.green-mid.green);
955  error.blue=QuantumScale*(pixel.blue-mid.blue);
956  if (cube_info->associate_alpha != MagickFalse)
957  error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
958  distance=(double) (error.red*error.red+error.green*error.green+
959  error.blue*error.blue+error.opacity*error.opacity);
960  if (IsNaN(distance) != 0)
961  distance=0.0;
962  node_info->quantize_error+=count*sqrt(distance);
963  cube_info->root->quantize_error+=node_info->quantize_error;
964  index--;
965  }
966  /*
967  Sum RGB for this leaf for later derivation of the mean cube color.
968  */
969  node_info->number_unique+=count;
970  node_info->total_color.red+=count*QuantumScale*(MagickRealType)
971  ClampPixel(pixel.red);
972  node_info->total_color.green+=count*QuantumScale*(MagickRealType)
973  ClampPixel(pixel.green);
974  node_info->total_color.blue+=count*QuantumScale*(MagickRealType)
975  ClampPixel(pixel.blue);
976  if (cube_info->associate_alpha != MagickFalse)
977  node_info->total_color.opacity+=count*QuantumScale*(MagickRealType)
978  ClampPixel(pixel.opacity);
979  else
980  node_info->total_color.opacity+=count*QuantumScale*(MagickRealType)
981  ClampPixel(OpaqueOpacity);
982  p+=(ptrdiff_t) count;
983  }
984  proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
985  image->rows);
986  if (proceed == MagickFalse)
987  break;
988  }
989  image_view=DestroyCacheView(image_view);
990  if (cube_info->quantize_info->colorspace != image->colorspace)
991  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
992  (cube_info->quantize_info->colorspace != CMYKColorspace))
993  (void) TransformImageColorspace((Image *) image,sRGBColorspace);
994  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
995 }
996 
997 /*
998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
999 % %
1000 % %
1001 % %
1002 % C l o n e Q u a n t i z e I n f o %
1003 % %
1004 % %
1005 % %
1006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007 %
1008 % CloneQuantizeInfo() makes a duplicate of the given quantize info structure,
1009 % or if quantize info is NULL, a new one.
1010 %
1011 % The format of the CloneQuantizeInfo method is:
1012 %
1013 % QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
1014 %
1015 % A description of each parameter follows:
1016 %
1017 % o clone_info: Method CloneQuantizeInfo returns a duplicate of the given
1018 % quantize info, or if image info is NULL a new one.
1019 %
1020 % o quantize_info: a structure of type info.
1021 %
1022 */
1023 MagickExport QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
1024 {
1025  QuantizeInfo
1026  *clone_info;
1027 
1028  clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
1029  if (clone_info == (QuantizeInfo *) NULL)
1030  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1031  GetQuantizeInfo(clone_info);
1032  if (quantize_info == (QuantizeInfo *) NULL)
1033  return(clone_info);
1034  clone_info->number_colors=quantize_info->number_colors;
1035  clone_info->tree_depth=quantize_info->tree_depth;
1036  clone_info->dither=quantize_info->dither;
1037  clone_info->dither_method=quantize_info->dither_method;
1038  clone_info->colorspace=quantize_info->colorspace;
1039  clone_info->measure_error=quantize_info->measure_error;
1040  return(clone_info);
1041 }
1042 
1043 /*
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 % %
1046 % %
1047 % %
1048 + C l o s e s t C o l o r %
1049 % %
1050 % %
1051 % %
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 %
1054 % ClosestColor() traverses the color cube tree at a particular node and
1055 % determines which colormap entry best represents the input color.
1056 %
1057 % The format of the ClosestColor method is:
1058 %
1059 % void ClosestColor(const Image *image,QCubeInfo *cube_info,
1060 % const QNodeInfo *node_info)
1061 %
1062 % A description of each parameter follows.
1063 %
1064 % o image: the image.
1065 %
1066 % o cube_info: A pointer to the Cube structure.
1067 %
1068 % o node_info: the address of a structure of type QNodeInfo which points to a
1069 % node in the color cube tree that is to be pruned.
1070 %
1071 */
1072 static void ClosestColor(const Image *image,QCubeInfo *cube_info,
1073  const QNodeInfo *node_info)
1074 {
1075  size_t
1076  number_children;
1077 
1078  ssize_t
1079  i;
1080 
1081  /*
1082  Traverse any children.
1083  */
1084  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
1085  for (i=0; i < (ssize_t) number_children; i++)
1086  if (node_info->child[i] != (QNodeInfo *) NULL)
1087  ClosestColor(image,cube_info,node_info->child[i]);
1088  if (node_info->number_unique != 0)
1089  {
1090  MagickRealType
1091  alpha,
1092  beta,
1093  distance,
1094  pixel;
1095 
1097  *magick_restrict q;
1098 
1099  PixelPacket
1100  *magick_restrict p;
1101 
1102  /*
1103  Determine if this color is "closest".
1104  */
1105  p=image->colormap+node_info->color_number;
1106  q=(&cube_info->target);
1107  alpha=1.0;
1108  beta=1.0;
1109  if (cube_info->associate_alpha != MagickFalse)
1110  {
1111  alpha=(MagickRealType) QuantumScale*GetPixelAlpha(p);
1112  beta=(MagickRealType) QuantumScale*GetPixelAlpha(q);
1113  }
1114  pixel=alpha*GetPixelRed(p)-beta*GetPixelRed(q);
1115  distance=pixel*pixel;
1116  if (distance <= cube_info->distance)
1117  {
1118  pixel=(MagickRealType) alpha*GetPixelGreen(p)-beta*GetPixelGreen(q);
1119  distance+=pixel*pixel;
1120  if (distance <= cube_info->distance)
1121  {
1122  pixel=(MagickRealType) alpha*GetPixelBlue(p)-beta*GetPixelBlue(q);
1123  distance+=pixel*pixel;
1124  if (distance <= cube_info->distance)
1125  {
1126  if (cube_info->associate_alpha != MagickFalse)
1127  {
1128  pixel=(MagickRealType) GetPixelAlpha(p)-GetPixelAlpha(q);
1129  distance+=pixel*pixel;
1130  }
1131  if (distance <= cube_info->distance)
1132  {
1133  cube_info->distance=distance;
1134  cube_info->color_number=node_info->color_number;
1135  }
1136  }
1137  }
1138  }
1139  }
1140 }
1141 
1142 /*
1143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 % %
1145 % %
1146 % %
1147 % C o m p r e s s I m a g e C o l o r m a p %
1148 % %
1149 % %
1150 % %
1151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 %
1153 % CompressImageColormap() compresses an image colormap by removing any
1154 % duplicate or unused color entries.
1155 %
1156 % The format of the CompressImageColormap method is:
1157 %
1158 % MagickBooleanType CompressImageColormap(Image *image)
1159 %
1160 % A description of each parameter follows:
1161 %
1162 % o image: the image.
1163 %
1164 */
1165 MagickExport MagickBooleanType CompressImageColormap(Image *image)
1166 {
1167  QuantizeInfo
1168  quantize_info;
1169 
1170  assert(image != (Image *) NULL);
1171  assert(image->signature == MagickCoreSignature);
1172  if (IsEventLogging() != MagickFalse)
1173  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1174  if (IsPaletteImage(image,&image->exception) == MagickFalse)
1175  return(MagickFalse);
1176  GetQuantizeInfo(&quantize_info);
1177  quantize_info.number_colors=image->colors;
1178  quantize_info.tree_depth=MaxTreeDepth;
1179  return(QuantizeImage(&quantize_info,image));
1180 }
1181 
1182 /*
1183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 % %
1185 % %
1186 % %
1187 + D e f i n e I m a g e C o l o r m a p %
1188 % %
1189 % %
1190 % %
1191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 %
1193 % DefineImageColormap() traverses the color cube tree and notes each colormap
1194 % entry. A colormap entry is any node in the color cube tree where the
1195 % of unique colors is not zero.
1196 %
1197 % The format of the DefineImageColormap method is:
1198 %
1199 % void DefineImageColormap(Image *image,QCubeInfo *cube_info,
1200 % QNodeInfo *node_info)
1201 %
1202 % A description of each parameter follows.
1203 %
1204 % o image: the image.
1205 %
1206 % o cube_info: A pointer to the Cube structure.
1207 %
1208 % o node_info: the address of a structure of type QNodeInfo which points to a
1209 % node in the color cube tree that is to be pruned.
1210 %
1211 */
1212 static void DefineImageColormap(Image *image,QCubeInfo *cube_info,
1213  QNodeInfo *node_info)
1214 {
1215  size_t
1216  number_children;
1217 
1218  ssize_t
1219  i;
1220 
1221  /*
1222  Traverse any children.
1223  */
1224  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
1225  for (i=0; i < (ssize_t) number_children; i++)
1226  if (node_info->child[i] != (QNodeInfo *) NULL)
1227  DefineImageColormap(image,cube_info,node_info->child[i]);
1228  if (node_info->number_unique != 0)
1229  {
1230  MagickRealType
1231  alpha;
1232 
1233  PixelPacket
1234  *magick_restrict q;
1235 
1236  /*
1237  Colormap entry is defined by the mean color in this cube.
1238  */
1239  q=image->colormap+image->colors;
1240  alpha=(MagickRealType) ((MagickOffsetType) node_info->number_unique);
1241  alpha=MagickSafeReciprocal(alpha);
1242  if (cube_info->associate_alpha == MagickFalse)
1243  {
1244  SetPixelRed(q,ClampToQuantum(alpha*(MagickRealType) QuantumRange*
1245  node_info->total_color.red));
1246  SetPixelGreen(q,ClampToQuantum(alpha*(MagickRealType) QuantumRange*
1247  node_info->total_color.green));
1248  SetPixelBlue(q,ClampToQuantum(alpha*(MagickRealType) QuantumRange*
1249  node_info->total_color.blue));
1250  SetPixelOpacity(q,OpaqueOpacity);
1251  }
1252  else
1253  {
1254  MagickRealType
1255  opacity;
1256 
1257  opacity=(MagickRealType) (alpha*(MagickRealType) QuantumRange*
1258  node_info->total_color.opacity);
1259  SetPixelOpacity(q,ClampToQuantum(opacity));
1260  if (q->opacity == OpaqueOpacity)
1261  {
1262  SetPixelRed(q,ClampToQuantum(alpha*(MagickRealType)
1263  QuantumRange*node_info->total_color.red));
1264  SetPixelGreen(q,ClampToQuantum(alpha*(MagickRealType)
1265  QuantumRange*node_info->total_color.green));
1266  SetPixelBlue(q,ClampToQuantum(alpha*(MagickRealType)
1267  QuantumRange*node_info->total_color.blue));
1268  }
1269  else
1270  {
1271  double
1272  gamma;
1273 
1274  gamma=(double) (QuantumScale*((double) QuantumRange-(double)
1275  q->opacity));
1276  gamma=MagickSafeReciprocal(gamma);
1277  SetPixelRed(q,ClampToQuantum(alpha*gamma*(MagickRealType)
1278  QuantumRange*node_info->total_color.red));
1279  SetPixelGreen(q,ClampToQuantum(alpha*gamma*(MagickRealType)
1280  QuantumRange*node_info->total_color.green));
1281  SetPixelBlue(q,ClampToQuantum(alpha*gamma*(MagickRealType)
1282  QuantumRange*node_info->total_color.blue));
1283  if (node_info->number_unique > cube_info->transparent_pixels)
1284  {
1285  cube_info->transparent_pixels=node_info->number_unique;
1286  cube_info->transparent_index=(ssize_t) image->colors;
1287  }
1288  }
1289  }
1290  node_info->color_number=image->colors++;
1291  }
1292 }
1293 
1294 /*
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296 % %
1297 % %
1298 % %
1299 + D e s t r o y Q C u b e I n f o %
1300 % %
1301 % %
1302 % %
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304 %
1305 % DestroyQCubeInfo() deallocates memory associated with an image.
1306 %
1307 % The format of the DestroyQCubeInfo method is:
1308 %
1309 % DestroyQCubeInfo(QCubeInfo *cube_info)
1310 %
1311 % A description of each parameter follows:
1312 %
1313 % o cube_info: the address of a structure of type QCubeInfo.
1314 %
1315 */
1316 static void DestroyQCubeInfo(QCubeInfo *cube_info)
1317 {
1318  QNodes
1319  *nodes;
1320 
1321  /*
1322  Release color cube tree storage.
1323  */
1324  do
1325  {
1326  nodes=cube_info->node_queue->next;
1327  cube_info->node_queue->nodes=(QNodeInfo *) RelinquishMagickMemory(
1328  cube_info->node_queue->nodes);
1329  cube_info->node_queue=(QNodes *) RelinquishMagickMemory(
1330  cube_info->node_queue);
1331  cube_info->node_queue=nodes;
1332  } while (cube_info->node_queue != (QNodes *) NULL);
1333  if (cube_info->memory_info != (MemoryInfo *) NULL)
1334  cube_info->memory_info=RelinquishVirtualMemory(cube_info->memory_info);
1335  cube_info->quantize_info=DestroyQuantizeInfo(cube_info->quantize_info);
1336  cube_info=(QCubeInfo *) RelinquishMagickMemory(cube_info);
1337 }
1338 
1339 /*
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 % %
1342 % %
1343 % %
1344 % D e s t r o y Q u a n t i z e I n f o %
1345 % %
1346 % %
1347 % %
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 %
1350 % DestroyQuantizeInfo() deallocates memory associated with an QuantizeInfo
1351 % structure.
1352 %
1353 % The format of the DestroyQuantizeInfo method is:
1354 %
1355 % QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
1356 %
1357 % A description of each parameter follows:
1358 %
1359 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
1360 %
1361 */
1362 MagickExport QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
1363 {
1364  assert(quantize_info != (QuantizeInfo *) NULL);
1365  assert(quantize_info->signature == MagickCoreSignature);
1366  if (IsEventLogging() != MagickFalse)
1367  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1368  quantize_info->signature=(~MagickCoreSignature);
1369  quantize_info=(QuantizeInfo *) RelinquishMagickMemory(quantize_info);
1370  return(quantize_info);
1371 }
1372 
1373 /*
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 % %
1376 % %
1377 % %
1378 + D i t h e r I m a g e %
1379 % %
1380 % %
1381 % %
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 %
1384 % DitherImage() distributes the difference between an original image and
1385 % the corresponding color reduced algorithm to neighboring pixels using
1386 % serpentine-scan Floyd-Steinberg error diffusion. DitherImage returns
1387 % MagickTrue if the image is dithered otherwise MagickFalse.
1388 %
1389 % The format of the DitherImage method is:
1390 %
1391 % MagickBooleanType DitherImage(Image *image,QCubeInfo *cube_info)
1392 %
1393 % A description of each parameter follows.
1394 %
1395 % o image: the image.
1396 %
1397 % o cube_info: A pointer to the Cube structure.
1398 %
1399 */
1400 
1401 static DoublePixelPacket **DestroyPixelTLS(DoublePixelPacket **pixels)
1402 {
1403  ssize_t
1404  i;
1405 
1406  assert(pixels != (DoublePixelPacket **) NULL);
1407  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
1408  if (pixels[i] != (DoublePixelPacket *) NULL)
1409  pixels[i]=(DoublePixelPacket *) RelinquishMagickMemory(pixels[i]);
1410  pixels=(DoublePixelPacket **) RelinquishMagickMemory(pixels);
1411  return(pixels);
1412 }
1413 
1414 static DoublePixelPacket **AcquirePixelTLS(const size_t count)
1415 {
1417  **pixels;
1418 
1419  size_t
1420  number_threads;
1421 
1422  ssize_t
1423  i;
1424 
1425  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
1426  pixels=(DoublePixelPacket **) AcquireQuantumMemory(number_threads,
1427  sizeof(*pixels));
1428  if (pixels == (DoublePixelPacket **) NULL)
1429  return((DoublePixelPacket **) NULL);
1430  (void) memset(pixels,0,number_threads*sizeof(*pixels));
1431  for (i=0; i < (ssize_t) number_threads; i++)
1432  {
1433  pixels[i]=(DoublePixelPacket *) AcquireQuantumMemory(count,2*
1434  sizeof(**pixels));
1435  if (pixels[i] == (DoublePixelPacket *) NULL)
1436  return(DestroyPixelTLS(pixels));
1437  }
1438  return(pixels);
1439 }
1440 
1441 static inline ssize_t CacheOffset(QCubeInfo *cube_info,
1442  const DoublePixelPacket *pixel)
1443 {
1444 #define RedShift(pixel) (((pixel) >> CacheShift) << (0*(8-CacheShift)))
1445 #define GreenShift(pixel) (((pixel) >> CacheShift) << (1*(8-CacheShift)))
1446 #define BlueShift(pixel) (((pixel) >> CacheShift) << (2*(8-CacheShift)))
1447 #define AlphaShift(pixel) (((pixel) >> CacheShift) << (3*(8-CacheShift)))
1448 
1449  ssize_t
1450  offset;
1451 
1452  offset=(ssize_t) (RedShift(ScaleQuantumToChar(ClampPixel(pixel->red))) |
1453  GreenShift(ScaleQuantumToChar(ClampPixel(pixel->green))) |
1454  BlueShift(ScaleQuantumToChar(ClampPixel(pixel->blue))));
1455  if (cube_info->associate_alpha != MagickFalse)
1456  offset|=AlphaShift(ScaleQuantumToChar(ClampPixel(pixel->opacity)));
1457  return(offset);
1458 }
1459 
1460 static MagickBooleanType FloydSteinbergDither(Image *image,QCubeInfo *cube_info)
1461 {
1462 #define DitherImageTag "Dither/Image"
1463 
1464  CacheView
1465  *image_view;
1466 
1468  **pixels;
1469 
1471  *exception;
1472 
1473  MagickBooleanType
1474  status;
1475 
1476  ssize_t
1477  y;
1478 
1479  /*
1480  Distribute quantization error using Floyd-Steinberg.
1481  */
1482  pixels=AcquirePixelTLS(image->columns);
1483  if (pixels == (DoublePixelPacket **) NULL)
1484  return(MagickFalse);
1485  exception=(&image->exception);
1486  status=MagickTrue;
1487  image_view=AcquireAuthenticCacheView(image,exception);
1488  for (y=0; y < (ssize_t) image->rows; y++)
1489  {
1490  const int
1491  id = GetOpenMPThreadId();
1492 
1494  *current,
1495  *previous;
1496 
1497  IndexPacket
1498  *magick_restrict indexes;
1499 
1500  PixelPacket
1501  *magick_restrict q;
1502 
1503  QCubeInfo
1504  cube;
1505 
1506  size_t
1507  index;
1508 
1509  ssize_t
1510  x,
1511  v;
1512 
1513  if (status == MagickFalse)
1514  continue;
1515  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1516  if (q == (PixelPacket *) NULL)
1517  {
1518  status=MagickFalse;
1519  continue;
1520  }
1521  indexes=GetCacheViewAuthenticIndexQueue(image_view);
1522  cube=(*cube_info);
1523  current=pixels[id]+(y & 0x01)*image->columns;
1524  previous=pixels[id]+((y+1) & 0x01)*image->columns;
1525  v=(ssize_t) ((y & 0x01) ? -1 : 1);
1526  for (x=0; x < (ssize_t) image->columns; x++)
1527  {
1529  color,
1530  pixel;
1531 
1532  ssize_t
1533  i;
1534 
1535  ssize_t
1536  u;
1537 
1538  u=(y & 0x01) ? (ssize_t) image->columns-1-x : x;
1539  AssociateAlphaPixel(&cube,q+u,&pixel);
1540  if (x > 0)
1541  {
1542  pixel.red+=7.0*cube_info->diffusion*current[u-v].red/16;
1543  pixel.green+=7.0*cube_info->diffusion*current[u-v].green/16;
1544  pixel.blue+=7.0*cube_info->diffusion*current[u-v].blue/16;
1545  if (cube.associate_alpha != MagickFalse)
1546  pixel.opacity+=7.0*cube_info->diffusion*current[u-v].opacity/16;
1547  }
1548  if (y > 0)
1549  {
1550  if (x < (ssize_t) (image->columns-1))
1551  {
1552  pixel.red+=cube_info->diffusion*previous[u+v].red/16;
1553  pixel.green+=cube_info->diffusion*previous[u+v].green/16;
1554  pixel.blue+=cube_info->diffusion*previous[u+v].blue/16;
1555  if (cube.associate_alpha != MagickFalse)
1556  pixel.opacity+=cube_info->diffusion*previous[u+v].opacity/16;
1557  }
1558  pixel.red+=5.0*cube_info->diffusion*previous[u].red/16;
1559  pixel.green+=5.0*cube_info->diffusion*previous[u].green/16;
1560  pixel.blue+=5.0*cube_info->diffusion*previous[u].blue/16;
1561  if (cube.associate_alpha != MagickFalse)
1562  pixel.opacity+=5.0*cube_info->diffusion*previous[u].opacity/16;
1563  if (x > 0)
1564  {
1565  pixel.red+=3.0*cube_info->diffusion*previous[u-v].red/16;
1566  pixel.green+=3.0*cube_info->diffusion*previous[u-v].green/16;
1567  pixel.blue+=3.0*cube_info->diffusion*previous[u-v].blue/16;
1568  if (cube.associate_alpha != MagickFalse)
1569  pixel.opacity+=3.0*cube_info->diffusion*
1570  previous[u-v].opacity/16;
1571  }
1572  }
1573  pixel.red=(MagickRealType) ClampPixel(pixel.red);
1574  pixel.green=(MagickRealType) ClampPixel(pixel.green);
1575  pixel.blue=(MagickRealType) ClampPixel(pixel.blue);
1576  if (cube.associate_alpha != MagickFalse)
1577  pixel.opacity=(MagickRealType) ClampPixel(pixel.opacity);
1578  i=CacheOffset(&cube,&pixel);
1579  if (cube.cache[i] < 0)
1580  {
1581  QNodeInfo
1582  *node_info;
1583 
1584  size_t
1585  id;
1586 
1587  /*
1588  Identify the deepest node containing the pixel's color.
1589  */
1590  node_info=cube.root;
1591  for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
1592  {
1593  id=ColorToQNodeId(&cube,&pixel,index);
1594  if (node_info->child[id] == (QNodeInfo *) NULL)
1595  break;
1596  node_info=node_info->child[id];
1597  }
1598  /*
1599  Find closest color among siblings and their children.
1600  */
1601  cube.target=pixel;
1602  cube.distance=(MagickRealType) (4.0*((MagickRealType) QuantumRange+
1603  1.0)*((MagickRealType) QuantumRange+1.0)+1.0);
1604  ClosestColor(image,&cube,node_info->parent);
1605  cube.cache[i]=(ssize_t) cube.color_number;
1606  }
1607  /*
1608  Assign pixel to closest colormap entry.
1609  */
1610  index=(size_t) cube.cache[i];
1611  if (image->storage_class == PseudoClass)
1612  SetPixelIndex(indexes+u,index);
1613  if (cube.quantize_info->measure_error == MagickFalse)
1614  {
1615  SetPixelRgb(q+u,image->colormap+index);
1616  if (cube.associate_alpha != MagickFalse)
1617  SetPixelOpacity(q+u,image->colormap[index].opacity);
1618  }
1619  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1620  status=MagickFalse;
1621  /*
1622  Store the error.
1623  */
1624  AssociateAlphaPixel(&cube,image->colormap+index,&color);
1625  current[u].red=pixel.red-color.red;
1626  current[u].green=pixel.green-color.green;
1627  current[u].blue=pixel.blue-color.blue;
1628  if (cube.associate_alpha != MagickFalse)
1629  current[u].opacity=pixel.opacity-color.opacity;
1630  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1631  {
1632  MagickBooleanType
1633  proceed;
1634 
1635  proceed=SetImageProgress(image,DitherImageTag,(MagickOffsetType) y,
1636  image->rows);
1637  if (proceed == MagickFalse)
1638  status=MagickFalse;
1639  }
1640  }
1641  }
1642  image_view=DestroyCacheView(image_view);
1643  pixels=DestroyPixelTLS(pixels);
1644  return(MagickTrue);
1645 }
1646 
1647 static MagickBooleanType
1648  RiemersmaDither(Image *,CacheView *,QCubeInfo *,const unsigned int);
1649 
1650 static MagickBooleanType Riemersma(Image *image,CacheView *image_view,
1651  QCubeInfo *cube_info,const size_t level,const unsigned int direction)
1652 {
1653  MagickStatusType
1654  status;
1655 
1656  status=MagickTrue;
1657  if (level == 1)
1658  switch (direction)
1659  {
1660  case WestGravity:
1661  {
1662  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1663  if (status != MagickFalse)
1664  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1665  if (status != MagickFalse)
1666  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1667  break;
1668  }
1669  case EastGravity:
1670  {
1671  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1672  if (status != MagickFalse)
1673  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1674  if (status != MagickFalse)
1675  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1676  break;
1677  }
1678  case NorthGravity:
1679  {
1680  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1681  if (status != MagickFalse)
1682  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1683  if (status != MagickFalse)
1684  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1685  break;
1686  }
1687  case SouthGravity:
1688  {
1689  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1690  if (status != MagickFalse)
1691  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1692  if (status != MagickFalse)
1693  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1694  break;
1695  }
1696  default:
1697  break;
1698  }
1699  else
1700  switch (direction)
1701  {
1702  case WestGravity:
1703  {
1704  status=Riemersma(image,image_view,cube_info,level-1,NorthGravity);
1705  if (status != MagickFalse)
1706  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1707  if (status != MagickFalse)
1708  status=Riemersma(image,image_view,cube_info,level-1,WestGravity);
1709  if (status != MagickFalse)
1710  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1711  if (status != MagickFalse)
1712  status=Riemersma(image,image_view,cube_info,level-1,WestGravity);
1713  if (status != MagickFalse)
1714  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1715  if (status != MagickFalse)
1716  status=Riemersma(image,image_view,cube_info,level-1,SouthGravity);
1717  break;
1718  }
1719  case EastGravity:
1720  {
1721  status=Riemersma(image,image_view,cube_info,level-1,SouthGravity);
1722  if (status != MagickFalse)
1723  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1724  if (status != MagickFalse)
1725  status=Riemersma(image,image_view,cube_info,level-1,EastGravity);
1726  if (status != MagickFalse)
1727  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1728  if (status != MagickFalse)
1729  status=Riemersma(image,image_view,cube_info,level-1,EastGravity);
1730  if (status != MagickFalse)
1731  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1732  if (status != MagickFalse)
1733  status=Riemersma(image,image_view,cube_info,level-1,NorthGravity);
1734  break;
1735  }
1736  case NorthGravity:
1737  {
1738  status=Riemersma(image,image_view,cube_info,level-1,WestGravity);
1739  if (status != MagickFalse)
1740  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1741  if (status != MagickFalse)
1742  status=Riemersma(image,image_view,cube_info,level-1,NorthGravity);
1743  if (status != MagickFalse)
1744  status=RiemersmaDither(image,image_view,cube_info,EastGravity);
1745  if (status != MagickFalse)
1746  status=Riemersma(image,image_view,cube_info,level-1,NorthGravity);
1747  if (status != MagickFalse)
1748  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1749  if (status != MagickFalse)
1750  status=Riemersma(image,image_view,cube_info,level-1,EastGravity);
1751  break;
1752  }
1753  case SouthGravity:
1754  {
1755  status=Riemersma(image,image_view,cube_info,level-1,EastGravity);
1756  if (status != MagickFalse)
1757  status=RiemersmaDither(image,image_view,cube_info,NorthGravity);
1758  if (status != MagickFalse)
1759  status=Riemersma(image,image_view,cube_info,level-1,SouthGravity);
1760  if (status != MagickFalse)
1761  status=RiemersmaDither(image,image_view,cube_info,WestGravity);
1762  if (status != MagickFalse)
1763  status=Riemersma(image,image_view,cube_info,level-1,SouthGravity);
1764  if (status != MagickFalse)
1765  status=RiemersmaDither(image,image_view,cube_info,SouthGravity);
1766  if (status != MagickFalse)
1767  status=Riemersma(image,image_view,cube_info,level-1,WestGravity);
1768  break;
1769  }
1770  default:
1771  break;
1772  }
1773  return(status != 0 ? MagickTrue : MagickFalse);
1774 }
1775 
1776 static MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
1777  QCubeInfo *cube_info,const unsigned int direction)
1778 {
1779 #define DitherImageTag "Dither/Image"
1780 
1782  color,
1783  pixel;
1784 
1785  MagickBooleanType
1786  proceed;
1787 
1788  QCubeInfo
1789  *p;
1790 
1791  size_t
1792  index;
1793 
1794  p=cube_info;
1795  if ((p->x >= 0) && (p->x < (ssize_t) image->columns) &&
1796  (p->y >= 0) && (p->y < (ssize_t) image->rows))
1797  {
1799  *exception;
1800 
1801  IndexPacket
1802  *magick_restrict indexes;
1803 
1804  PixelPacket
1805  *magick_restrict q;
1806 
1807  ssize_t
1808  i;
1809 
1810  /*
1811  Distribute error.
1812  */
1813  exception=(&image->exception);
1814  q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
1815  if (q == (PixelPacket *) NULL)
1816  return(MagickFalse);
1817  indexes=GetCacheViewAuthenticIndexQueue(image_view);
1818  AssociateAlphaPixel(cube_info,q,&pixel);
1819  for (i=0; i < ErrorQueueLength; i++)
1820  {
1821  pixel.red+=ErrorRelativeWeight*cube_info->diffusion*p->weights[i]*
1822  p->error[i].red;
1823  pixel.green+=ErrorRelativeWeight*cube_info->diffusion*p->weights[i]*
1824  p->error[i].green;
1825  pixel.blue+=ErrorRelativeWeight*cube_info->diffusion*p->weights[i]*
1826  p->error[i].blue;
1827  if (cube_info->associate_alpha != MagickFalse)
1828  pixel.opacity+=ErrorRelativeWeight*cube_info->diffusion*p->weights[i]*
1829  p->error[i].opacity;
1830  }
1831  pixel.red=(MagickRealType) ClampPixel(pixel.red);
1832  pixel.green=(MagickRealType) ClampPixel(pixel.green);
1833  pixel.blue=(MagickRealType) ClampPixel(pixel.blue);
1834  if (cube_info->associate_alpha != MagickFalse)
1835  pixel.opacity=(MagickRealType) ClampPixel(pixel.opacity);
1836  i=CacheOffset(cube_info,&pixel);
1837  if (p->cache[i] < 0)
1838  {
1839  QNodeInfo
1840  *node_info;
1841 
1842  size_t
1843  id;
1844 
1845  /*
1846  Identify the deepest node containing the pixel's color.
1847  */
1848  node_info=p->root;
1849  for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
1850  {
1851  id=ColorToQNodeId(cube_info,&pixel,index);
1852  if (node_info->child[id] == (QNodeInfo *) NULL)
1853  break;
1854  node_info=node_info->child[id];
1855  }
1856  /*
1857  Find closest color among siblings and their children.
1858  */
1859  p->target=pixel;
1860  p->distance=(MagickRealType) (4.0*((MagickRealType) QuantumRange+
1861  1.0)*((MagickRealType) QuantumRange+1.0)+1.0);
1862  ClosestColor(image,p,node_info->parent);
1863  p->cache[i]=(ssize_t) p->color_number;
1864  }
1865  /*
1866  Assign pixel to closest colormap entry.
1867  */
1868  index=(size_t) (1*p->cache[i]);
1869  if (image->storage_class == PseudoClass)
1870  *indexes=(IndexPacket) index;
1871  if (cube_info->quantize_info->measure_error == MagickFalse)
1872  {
1873  SetPixelRgb(q,image->colormap+index);
1874  if (cube_info->associate_alpha != MagickFalse)
1875  SetPixelOpacity(q,image->colormap[index].opacity);
1876  }
1877  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1878  return(MagickFalse);
1879  /*
1880  Propagate the error as the last entry of the error queue.
1881  */
1882  (void) memmove(p->error,p->error+1,(ErrorQueueLength-1)*
1883  sizeof(p->error[0]));
1884  AssociateAlphaPixel(cube_info,image->colormap+index,&color);
1885  p->error[ErrorQueueLength-1].red=pixel.red-color.red;
1886  p->error[ErrorQueueLength-1].green=pixel.green-color.green;
1887  p->error[ErrorQueueLength-1].blue=pixel.blue-color.blue;
1888  if (cube_info->associate_alpha != MagickFalse)
1889  p->error[ErrorQueueLength-1].opacity=pixel.opacity-color.opacity;
1890  proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
1891  if (proceed == MagickFalse)
1892  return(MagickFalse);
1893  p->offset++;
1894  }
1895  switch (direction)
1896  {
1897  case WestGravity: p->x--; break;
1898  case EastGravity: p->x++; break;
1899  case NorthGravity: p->y--; break;
1900  case SouthGravity: p->y++; break;
1901  }
1902  return(MagickTrue);
1903 }
1904 
1905 static MagickBooleanType DitherImage(Image *image,QCubeInfo *cube_info)
1906 {
1907  CacheView
1908  *image_view;
1909 
1910  const char
1911  *artifact;
1912 
1913  MagickBooleanType
1914  status;
1915 
1916  size_t
1917  extent,
1918  level;
1919 
1920  artifact=GetImageArtifact(image,"dither:diffusion-amount");
1921  if (artifact != (const char *) NULL)
1922  cube_info->diffusion=StringToDoubleInterval(artifact,1.0);
1923  if (cube_info->quantize_info->dither_method != RiemersmaDitherMethod)
1924  return(FloydSteinbergDither(image,cube_info));
1925  /*
1926  Distribute quantization error along a Hilbert curve.
1927  */
1928  (void) memset(cube_info->error,0,ErrorQueueLength*sizeof(*cube_info->error));
1929  cube_info->x=0;
1930  cube_info->y=0;
1931  extent=MagickMax(image->columns,image->rows);
1932  level=(size_t) log2((double) extent);
1933  if ((1UL << level) < extent)
1934  level++;
1935  cube_info->offset=0;
1936  cube_info->span=(MagickSizeType) image->columns*image->rows;
1937  image_view=AcquireAuthenticCacheView(image,&image->exception);
1938  status=MagickTrue;
1939  if (level > 0)
1940  status=Riemersma(image,image_view,cube_info,level,NorthGravity);
1941  if (status != MagickFalse)
1942  status=RiemersmaDither(image,image_view,cube_info,ForgetGravity);
1943  image_view=DestroyCacheView(image_view);
1944  return(status);
1945 }
1946 
1947 /*
1948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1949 % %
1950 % %
1951 % %
1952 + G e t Q C u b e I n f o %
1953 % %
1954 % %
1955 % %
1956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957 %
1958 % GetQCubeInfo() initialize the Cube data structure.
1959 %
1960 % The format of the GetQCubeInfo method is:
1961 %
1962 % QCubeInfo GetQCubeInfo(const QuantizeInfo *quantize_info,
1963 % const size_t depth,const size_t maximum_colors)
1964 %
1965 % A description of each parameter follows.
1966 %
1967 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
1968 %
1969 % o depth: Normally, this integer value is zero or one. A zero or
1970 % one tells Quantize to choose a optimal tree depth of Log4(number_colors).
1971 % A tree of this depth generally allows the best representation of the
1972 % reference image with the least amount of memory and the fastest
1973 % computational speed. In some cases, such as an image with low color
1974 % dispersion (a few number of colors), a value other than
1975 % Log4(number_colors) is required. To expand the color tree completely,
1976 % use a value of 8.
1977 %
1978 % o maximum_colors: maximum colors.
1979 %
1980 */
1981 static QCubeInfo *GetQCubeInfo(const QuantizeInfo *quantize_info,
1982  const size_t depth,const size_t maximum_colors)
1983 {
1984  MagickRealType
1985  weight;
1986 
1987  QCubeInfo
1988  *cube_info;
1989 
1990  size_t
1991  length;
1992 
1993  ssize_t
1994  i;
1995 
1996  /*
1997  Initialize tree to describe color cube_info.
1998  */
1999  cube_info=(QCubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
2000  if (cube_info == (QCubeInfo *) NULL)
2001  return((QCubeInfo *) NULL);
2002  (void) memset(cube_info,0,sizeof(*cube_info));
2003  cube_info->depth=depth;
2004  if (cube_info->depth > MaxTreeDepth)
2005  cube_info->depth=MaxTreeDepth;
2006  if (cube_info->depth < 2)
2007  cube_info->depth=2;
2008  cube_info->maximum_colors=maximum_colors;
2009  /*
2010  Initialize root node.
2011  */
2012  cube_info->root=GetQNodeInfo(cube_info,0,0,(QNodeInfo *) NULL);
2013  if (cube_info->root == (QNodeInfo *) NULL)
2014  return((QCubeInfo *) NULL);
2015  cube_info->root->parent=cube_info->root;
2016  cube_info->quantize_info=CloneQuantizeInfo(quantize_info);
2017  if (cube_info->quantize_info->dither == MagickFalse)
2018  return(cube_info);
2019  /*
2020  Initialize dither resources.
2021  */
2022  length=(size_t) (1UL << (4*(8-CacheShift)));
2023  cube_info->memory_info=AcquireVirtualMemory(length,sizeof(*cube_info->cache));
2024  if (cube_info->memory_info == (MemoryInfo *) NULL)
2025  return((QCubeInfo *) NULL);
2026  cube_info->cache=(ssize_t *) GetVirtualMemoryBlob(cube_info->memory_info);
2027  /*
2028  Initialize color cache.
2029  */
2030  (void) memset(cube_info->cache,(-1),sizeof(*cube_info->cache)*length);
2031  /*
2032  Distribute weights along a curve of exponential decay.
2033  */
2034  weight=1.0;
2035  for (i=0; i < ErrorQueueLength; i++)
2036  {
2037  cube_info->weights[i]=MagickSafeReciprocal(weight);
2038  weight*=exp(log(1.0/ErrorRelativeWeight)/(ErrorQueueLength-1.0));
2039  }
2040  cube_info->diffusion=1.0;
2041  return(cube_info);
2042 }
2043 
2044 /*
2045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2046 % %
2047 % %
2048 % %
2049 + G e t N o d e I n f o %
2050 % %
2051 % %
2052 % %
2053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054 %
2055 % GetQNodeInfo() allocates memory for a new node in the color cube tree and
2056 % presets all fields to zero.
2057 %
2058 % The format of the GetQNodeInfo method is:
2059 %
2060 % QNodeInfo *GetQNodeInfo(QCubeInfo *cube_info,const size_t id,
2061 % const size_t level,QNodeInfo *parent)
2062 %
2063 % A description of each parameter follows.
2064 %
2065 % o node: The GetQNodeInfo method returns a pointer to a queue of nodes.
2066 %
2067 % o id: Specifies the child number of the node.
2068 %
2069 % o level: Specifies the level in the storage_class the node resides.
2070 %
2071 */
2072 static QNodeInfo *GetQNodeInfo(QCubeInfo *cube_info,const size_t id,
2073  const size_t level,QNodeInfo *parent)
2074 {
2075  QNodeInfo
2076  *node_info;
2077 
2078  if (cube_info->free_nodes == 0)
2079  {
2080  QNodes
2081  *nodes;
2082 
2083  /*
2084  Allocate a new queue of nodes.
2085  */
2086  nodes=(QNodes *) AcquireMagickMemory(sizeof(*nodes));
2087  if (nodes == (QNodes *) NULL)
2088  return((QNodeInfo *) NULL);
2089  nodes->nodes=(QNodeInfo *) AcquireQuantumMemory(QNodesInAList,
2090  sizeof(*nodes->nodes));
2091  if (nodes->nodes == (QNodeInfo *) NULL)
2092  return((QNodeInfo *) NULL);
2093  nodes->next=cube_info->node_queue;
2094  cube_info->node_queue=nodes;
2095  cube_info->next_node=nodes->nodes;
2096  cube_info->free_nodes=QNodesInAList;
2097  }
2098  cube_info->nodes++;
2099  cube_info->free_nodes--;
2100  node_info=cube_info->next_node++;
2101  (void) memset(node_info,0,sizeof(*node_info));
2102  node_info->parent=parent;
2103  node_info->id=id;
2104  node_info->level=level;
2105  return(node_info);
2106 }
2107 
2108 /*
2109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110 % %
2111 % %
2112 % %
2113 % G e t I m a g e Q u a n t i z e E r r o r %
2114 % %
2115 % %
2116 % %
2117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118 %
2119 % GetImageQuantizeError() measures the difference between the original
2120 % and quantized images. This difference is the total quantization error.
2121 % The error is computed by summing over all pixels in an image the distance
2122 % squared in RGB space between each reference pixel value and its quantized
2123 % value. These values are computed:
2124 %
2125 % o mean_error_per_pixel: This value is the mean error for any single
2126 % pixel in the image.
2127 %
2128 % o normalized_mean_square_error: This value is the normalized mean
2129 % quantization error for any single pixel in the image. This distance
2130 % measure is normalized to a range between 0 and 1. It is independent
2131 % of the range of red, green, and blue values in the image.
2132 %
2133 % o normalized_maximum_square_error: This value is the normalized
2134 % maximum quantization error for any single pixel in the image. This
2135 % distance measure is normalized to a range between 0 and 1. It is
2136 % independent of the range of red, green, and blue values in your image.
2137 %
2138 % The format of the GetImageQuantizeError method is:
2139 %
2140 % MagickBooleanType GetImageQuantizeError(Image *image)
2141 %
2142 % A description of each parameter follows.
2143 %
2144 % o image: the image.
2145 %
2146 */
2147 MagickExport MagickBooleanType GetImageQuantizeError(Image *image)
2148 {
2149  CacheView
2150  *image_view;
2151 
2153  *exception;
2154 
2155  IndexPacket
2156  *indexes;
2157 
2158  MagickRealType
2159  alpha,
2160  area,
2161  beta,
2162  distance,
2163  gamma,
2164  maximum_error,
2165  mean_error,
2166  mean_error_per_pixel;
2167 
2168  ssize_t
2169  index,
2170  y;
2171 
2172  assert(image != (Image *) NULL);
2173  assert(image->signature == MagickCoreSignature);
2174  if (IsEventLogging() != MagickFalse)
2175  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2176  image->total_colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
2177  (void) memset(&image->error,0,sizeof(image->error));
2178  if (image->storage_class == DirectClass)
2179  return(MagickTrue);
2180  alpha=1.0;
2181  beta=1.0;
2182  area=3.0*image->columns*image->rows;
2183  maximum_error=0.0;
2184  mean_error_per_pixel=0.0;
2185  mean_error=0.0;
2186  exception=(&image->exception);
2187  image_view=AcquireVirtualCacheView(image,exception);
2188  for (y=0; y < (ssize_t) image->rows; y++)
2189  {
2190  const PixelPacket
2191  *magick_restrict p;
2192 
2193  ssize_t
2194  x;
2195 
2196  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2197  if (p == (const PixelPacket *) NULL)
2198  break;
2199  indexes=GetCacheViewAuthenticIndexQueue(image_view);
2200  for (x=0; x < (ssize_t) image->columns; x++)
2201  {
2202  index=(ssize_t) GetPixelIndex(indexes+x);
2203  if (image->matte != MagickFalse)
2204  {
2205  alpha=QuantumScale*(MagickRealType) GetPixelAlpha(p);
2206  beta=QuantumScale*((MagickRealType) QuantumRange-
2207  (MagickRealType) image->colormap[index].opacity);
2208  }
2209  distance=fabs((double) (alpha*(MagickRealType) GetPixelRed(p)-beta*
2210  (MagickRealType) image->colormap[index].red));
2211  mean_error_per_pixel+=distance;
2212  mean_error+=distance*distance;
2213  if (distance > maximum_error)
2214  maximum_error=distance;
2215  distance=fabs((double) (alpha*(MagickRealType) GetPixelGreen(p)-beta*
2216  (MagickRealType) image->colormap[index].green));
2217  mean_error_per_pixel+=distance;
2218  mean_error+=distance*distance;
2219  if (distance > maximum_error)
2220  maximum_error=distance;
2221  distance=fabs((double) (alpha*(MagickRealType) GetPixelBlue(p)-beta*
2222  (MagickRealType) image->colormap[index].blue));
2223  mean_error_per_pixel+=distance;
2224  mean_error+=distance*distance;
2225  if (distance > maximum_error)
2226  maximum_error=distance;
2227  p++;
2228  }
2229  }
2230  image_view=DestroyCacheView(image_view);
2231  gamma=MagickSafeReciprocal(area);
2232  image->error.mean_error_per_pixel=gamma*mean_error_per_pixel;
2233  image->error.normalized_mean_error=gamma*QuantumScale*QuantumScale*mean_error;
2234  image->error.normalized_maximum_error=QuantumScale*maximum_error;
2235  return(MagickTrue);
2236 }
2237 
2238 /*
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 % %
2241 % %
2242 % %
2243 % G e t Q u a n t i z e I n f o %
2244 % %
2245 % %
2246 % %
2247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248 %
2249 % GetQuantizeInfo() initializes the QuantizeInfo structure.
2250 %
2251 % The format of the GetQuantizeInfo method is:
2252 %
2253 % GetQuantizeInfo(QuantizeInfo *quantize_info)
2254 %
2255 % A description of each parameter follows:
2256 %
2257 % o quantize_info: Specifies a pointer to a QuantizeInfo structure.
2258 %
2259 */
2260 MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
2261 {
2262  assert(quantize_info != (QuantizeInfo *) NULL);
2263  if (IsEventLogging() != MagickFalse)
2264  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2265  (void) memset(quantize_info,0,sizeof(*quantize_info));
2266  quantize_info->number_colors=256;
2267  quantize_info->dither=MagickTrue;
2268  quantize_info->dither_method=RiemersmaDitherMethod;
2269  quantize_info->colorspace=UndefinedColorspace;
2270  quantize_info->measure_error=MagickFalse;
2271  quantize_info->signature=MagickCoreSignature;
2272 }
2273 
2274 /*
2275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 % %
2277 % %
2278 % %
2279 % P o s t e r i z e I m a g e C h a n n e l %
2280 % %
2281 % %
2282 % %
2283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 %
2285 % PosterizeImage() reduces the image to a limited number of colors for a
2286 % "poster" effect.
2287 %
2288 % The format of the PosterizeImage method is:
2289 %
2290 % MagickBooleanType PosterizeImage(Image *image,const size_t levels,
2291 % const MagickBooleanType dither)
2292 % MagickBooleanType PosterizeImageChannel(Image *image,
2293 % const ChannelType channel,const size_t levels,
2294 % const MagickBooleanType dither)
2295 %
2296 % A description of each parameter follows:
2297 %
2298 % o image: Specifies a pointer to an Image structure.
2299 %
2300 % o levels: Number of color levels allowed in each channel. Very low values
2301 % (2, 3, or 4) have the most visible effect.
2302 %
2303 % o dither: Set this integer value to something other than zero to dither
2304 % the mapped image.
2305 %
2306 */
2307 
2308 MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
2309  const MagickBooleanType dither)
2310 {
2311  MagickBooleanType
2312  status;
2313 
2314  status=PosterizeImageChannel(image,DefaultChannels,levels,dither);
2315  return(status);
2316 }
2317 
2318 static inline Quantum PosterizePixel(const Quantum pixel,const size_t levels)
2319 {
2320  double
2321  step_size;
2322 
2323  size_t
2324  level_index;
2325 
2326  if (levels < 2)
2327  return(pixel);
2328  step_size=1.0/(levels-1.0);
2329  level_index=(step_size == 0.0) ? 0 : floor((double) pixel/step_size);
2330  return(ClampToQuantum(level_index*step_size));
2331 }
2332 
2333 MagickExport MagickBooleanType PosterizeImageChannel(Image *image,
2334  const ChannelType channel,const size_t levels,const MagickBooleanType dither)
2335 {
2336 #define PosterizeImageTag "Posterize/Image"
2337 
2338  CacheView
2339  *image_view;
2340 
2342  *exception;
2343 
2344  MagickBooleanType
2345  status;
2346 
2347  MagickOffsetType
2348  progress;
2349 
2350  QuantizeInfo
2351  *quantize_info;
2352 
2353  ssize_t
2354  i,
2355  y;
2356 
2357  assert(image != (Image *) NULL);
2358  assert(image->signature == MagickCoreSignature);
2359  if (IsEventLogging() != MagickFalse)
2360  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2361  if (image->storage_class == PseudoClass)
2362 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2363  #pragma omp parallel for schedule(static) shared(progress,status) \
2364  magick_number_threads(image,image,image->colors,1)
2365 #endif
2366  for (i=0; i < (ssize_t) image->colors; i++)
2367  {
2368  /*
2369  Posterize colormap.
2370  */
2371  if ((channel & RedChannel) != 0)
2372  image->colormap[i].red=(MagickRealType)
2373  PosterizePixel(image->colormap[i].red,levels);
2374  if ((channel & GreenChannel) != 0)
2375  image->colormap[i].green=(MagickRealType)
2376  PosterizePixel(image->colormap[i].green,levels);
2377  if ((channel & BlueChannel) != 0)
2378  image->colormap[i].blue=(MagickRealType)
2379  PosterizePixel(image->colormap[i].blue,levels);
2380  if ((channel & OpacityChannel) != 0)
2381  image->colormap[i].opacity=(MagickRealType)
2382  PosterizePixel(image->colormap[i].opacity,levels);
2383  }
2384  /*
2385  Posterize image.
2386  */
2387  status=MagickTrue;
2388  progress=0;
2389  exception=(&image->exception);
2390  image_view=AcquireAuthenticCacheView(image,exception);
2391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2392  #pragma omp parallel for schedule(static) shared(progress,status) \
2393  magick_number_threads(image,image,image->rows,1)
2394 #endif
2395  for (y=0; y < (ssize_t) image->rows; y++)
2396  {
2397  IndexPacket
2398  *magick_restrict indexes;
2399 
2400  PixelPacket
2401  *magick_restrict q;
2402 
2403  ssize_t
2404  x;
2405 
2406  if (status == MagickFalse)
2407  continue;
2408  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2409  if (q == (PixelPacket *) NULL)
2410  {
2411  status=MagickFalse;
2412  continue;
2413  }
2414  indexes=GetCacheViewAuthenticIndexQueue(image_view);
2415  for (x=0; x < (ssize_t) image->columns; x++)
2416  {
2417  if ((channel & RedChannel) != 0)
2418  SetPixelRed(q,PosterizePixel(GetPixelRed(q),levels));
2419  if ((channel & GreenChannel) != 0)
2420  SetPixelGreen(q,PosterizePixel(GetPixelGreen(q),levels));
2421  if ((channel & BlueChannel) != 0)
2422  SetPixelBlue(q,PosterizePixel(GetPixelBlue(q),levels));
2423  if (((channel & OpacityChannel) != 0) &&
2424  (image->matte != MagickFalse))
2425  SetPixelOpacity(q,PosterizePixel(GetPixelOpacity(q),levels));
2426  if (((channel & IndexChannel) != 0) &&
2427  (image->colorspace == CMYKColorspace))
2428  SetPixelIndex(indexes+x,PosterizePixel(GetPixelIndex(indexes+x),
2429  levels));
2430  q++;
2431  }
2432  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2433  status=MagickFalse;
2434  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2435  {
2436  MagickBooleanType
2437  proceed;
2438 
2439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2440  #pragma omp atomic
2441 #endif
2442  progress++;
2443  proceed=SetImageProgress(image,PosterizeImageTag,progress,image->rows);
2444  if (proceed == MagickFalse)
2445  status=MagickFalse;
2446  }
2447  }
2448  image_view=DestroyCacheView(image_view);
2449  quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
2450  quantize_info->number_colors=(size_t) MagickMin((ssize_t) levels*levels*
2451  levels,MaxColormapSize);
2452  quantize_info->dither=dither;
2453  status=QuantizeImage(quantize_info,image);
2454  quantize_info=DestroyQuantizeInfo(quantize_info);
2455  return(status);
2456 }
2457 
2458 /*
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460 % %
2461 % %
2462 % %
2463 + P r u n e C h i l d %
2464 % %
2465 % %
2466 % %
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468 %
2469 % PruneChild() deletes the given node and merges its statistics into its
2470 % parent.
2471 %
2472 % The format of the PruneSubtree method is:
2473 %
2474 % PruneChild(QCubeInfo *cube_info,const QNodeInfo *node_info)
2475 %
2476 % A description of each parameter follows.
2477 %
2478 % o cube_info: A pointer to the Cube structure.
2479 %
2480 % o node_info: pointer to node in color cube tree that is to be pruned.
2481 %
2482 */
2483 static void PruneChild(QCubeInfo *cube_info,const QNodeInfo *node_info)
2484 {
2485  QNodeInfo
2486  *parent;
2487 
2488  size_t
2489  number_children;
2490 
2491  ssize_t
2492  i;
2493 
2494  /*
2495  Traverse any children.
2496  */
2497  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2498  for (i=0; i < (ssize_t) number_children; i++)
2499  if (node_info->child[i] != (QNodeInfo *) NULL)
2500  PruneChild(cube_info,node_info->child[i]);
2501  if (cube_info->nodes > cube_info->maximum_colors)
2502  {
2503  /*
2504  Merge color statistics into parent.
2505  */
2506  parent=node_info->parent;
2507  parent->number_unique+=node_info->number_unique;
2508  parent->total_color.red+=node_info->total_color.red;
2509  parent->total_color.green+=node_info->total_color.green;
2510  parent->total_color.blue+=node_info->total_color.blue;
2511  parent->total_color.opacity+=node_info->total_color.opacity;
2512  parent->child[node_info->id]=(QNodeInfo *) NULL;
2513  cube_info->nodes--;
2514  }
2515 }
2516 
2517 /*
2518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2519 % %
2520 % %
2521 % %
2522 + P r u n e L e v e l %
2523 % %
2524 % %
2525 % %
2526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527 %
2528 % PruneLevel() deletes all nodes at the bottom level of the color tree merging
2529 % their color statistics into their parent node.
2530 %
2531 % The format of the PruneLevel method is:
2532 %
2533 % PruneLevel(QCubeInfo *cube_info,const QNodeInfo *node_info)
2534 %
2535 % A description of each parameter follows.
2536 %
2537 % o cube_info: A pointer to the Cube structure.
2538 %
2539 % o node_info: pointer to node in color cube tree that is to be pruned.
2540 %
2541 */
2542 static void PruneLevel(QCubeInfo *cube_info,const QNodeInfo *node_info)
2543 {
2544  size_t
2545  number_children;
2546 
2547  ssize_t
2548  i;
2549 
2550  /*
2551  Traverse any children.
2552  */
2553  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2554  for (i=0; i < (ssize_t) number_children; i++)
2555  if (node_info->child[i] != (QNodeInfo *) NULL)
2556  PruneLevel(cube_info,node_info->child[i]);
2557  if (node_info->level == cube_info->depth)
2558  PruneChild(cube_info,node_info);
2559 }
2560 
2561 /*
2562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563 % %
2564 % %
2565 % %
2566 + P r u n e T o C u b e D e p t h %
2567 % %
2568 % %
2569 % %
2570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571 %
2572 % PruneToCubeDepth() deletes any nodes at a depth greater than
2573 % cube_info->depth while merging their color statistics into their parent
2574 % node.
2575 %
2576 % The format of the PruneToCubeDepth method is:
2577 %
2578 % PruneToCubeDepth(QCubeInfo *cube_info,const QNodeInfo *node_info)
2579 %
2580 % A description of each parameter follows.
2581 %
2582 % o cube_info: A pointer to the Cube structure.
2583 %
2584 % o node_info: pointer to node in color cube tree that is to be pruned.
2585 %
2586 */
2587 static void PruneToCubeDepth(QCubeInfo *cube_info,const QNodeInfo *node_info)
2588 {
2589  size_t
2590  number_children;
2591 
2592  ssize_t
2593  i;
2594 
2595  /*
2596  Traverse any children.
2597  */
2598  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2599  for (i=0; i < (ssize_t) number_children; i++)
2600  if (node_info->child[i] != (QNodeInfo *) NULL)
2601  PruneToCubeDepth(cube_info,node_info->child[i]);
2602  if (node_info->level > cube_info->depth)
2603  PruneChild(cube_info,node_info);
2604 }
2605 
2606 /*
2607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2608 % %
2609 % %
2610 % %
2611 % Q u a n t i z e I m a g e %
2612 % %
2613 % %
2614 % %
2615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2616 %
2617 % QuantizeImage() analyzes the colors within a reference image and chooses a
2618 % fixed number of colors to represent the image. The goal of the algorithm
2619 % is to minimize the color difference between the input and output image while
2620 % minimizing the processing time.
2621 %
2622 % The format of the QuantizeImage method is:
2623 %
2624 % MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
2625 % Image *image)
2626 %
2627 % A description of each parameter follows:
2628 %
2629 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
2630 %
2631 % o image: the image.
2632 %
2633 */
2634 MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
2635  Image *image)
2636 {
2637  MagickBooleanType
2638  status;
2639 
2640  QCubeInfo
2641  *cube_info;
2642 
2643  size_t
2644  depth,
2645  maximum_colors;
2646 
2647  assert(quantize_info != (const QuantizeInfo *) NULL);
2648  assert(quantize_info->signature == MagickCoreSignature);
2649  assert(image != (Image *) NULL);
2650  assert(image->signature == MagickCoreSignature);
2651  if (IsEventLogging() != MagickFalse)
2652  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2653  maximum_colors=quantize_info->number_colors;
2654  if (maximum_colors == 0)
2655  maximum_colors=MaxColormapSize;
2656  if (maximum_colors > MaxColormapSize)
2657  maximum_colors=MaxColormapSize;
2658  if (image->matte == MagickFalse)
2659  {
2660  if (SetImageGray(image,&image->exception) != MagickFalse)
2661  (void) SetGrayscaleImage(image);
2662  }
2663  depth=quantize_info->tree_depth;
2664  if (depth == 0)
2665  {
2666  size_t
2667  colors;
2668 
2669  /*
2670  Depth of color tree is: Log4(colormap size)+2.
2671  */
2672  colors=maximum_colors;
2673  for (depth=1; colors != 0; depth++)
2674  colors>>=2;
2675  if ((quantize_info->dither != MagickFalse) && (depth > 2))
2676  depth--;
2677  if ((image->matte != MagickFalse) && (depth > 5))
2678  depth--;
2679  if (SetImageGray(image,&image->exception) != MagickFalse)
2680  depth=MaxTreeDepth;
2681  }
2682  /*
2683  Initialize color cube.
2684  */
2685  cube_info=GetQCubeInfo(quantize_info,depth,maximum_colors);
2686  if (cube_info == (QCubeInfo *) NULL)
2687  ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
2688  image->filename);
2689  status=ClassifyImageColors(cube_info,image,&image->exception);
2690  if (status != MagickFalse)
2691  {
2692  /*
2693  Reduce the number of colors in the image.
2694  */
2695  if (cube_info->colors > cube_info->maximum_colors)
2696  ReduceImageColors(image,cube_info);
2697  status=AssignImageColors(image,cube_info);
2698  }
2699  DestroyQCubeInfo(cube_info);
2700  return(status);
2701 }
2702 
2703 /*
2704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2705 % %
2706 % %
2707 % %
2708 % Q u a n t i z e I m a g e s %
2709 % %
2710 % %
2711 % %
2712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713 %
2714 % QuantizeImages() analyzes the colors within a set of reference images and
2715 % chooses a fixed number of colors to represent the set. The goal of the
2716 % algorithm is to minimize the color difference between the input and output
2717 % images while minimizing the processing time.
2718 %
2719 % The format of the QuantizeImages method is:
2720 %
2721 % MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
2722 % Image *images)
2723 %
2724 % A description of each parameter follows:
2725 %
2726 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
2727 %
2728 % o images: Specifies a pointer to a list of Image structures.
2729 %
2730 */
2731 MagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
2732  Image *images)
2733 {
2734  Image
2735  *image;
2736 
2737  MagickBooleanType
2738  proceed,
2739  status;
2740 
2741  MagickProgressMonitor
2742  progress_monitor;
2743 
2744  QCubeInfo
2745  *cube_info;
2746 
2747  size_t
2748  depth,
2749  maximum_colors,
2750  number_images;
2751 
2752  ssize_t
2753  i;
2754 
2755  assert(quantize_info != (const QuantizeInfo *) NULL);
2756  assert(quantize_info->signature == MagickCoreSignature);
2757  assert(images != (Image *) NULL);
2758  assert(images->signature == MagickCoreSignature);
2759  if (IsEventLogging() != MagickFalse)
2760  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
2761  if (GetNextImageInList(images) == (Image *) NULL)
2762  {
2763  /*
2764  Handle a single image with QuantizeImage.
2765  */
2766  status=QuantizeImage(quantize_info,images);
2767  return(status);
2768  }
2769  status=MagickFalse;
2770  maximum_colors=quantize_info->number_colors;
2771  if (maximum_colors == 0)
2772  maximum_colors=MaxColormapSize;
2773  if (maximum_colors > MaxColormapSize)
2774  maximum_colors=MaxColormapSize;
2775  depth=quantize_info->tree_depth;
2776  if (depth == 0)
2777  {
2778  size_t
2779  colors;
2780 
2781  /*
2782  Depth of color tree is: Log4(colormap size)+2.
2783  */
2784  colors=maximum_colors;
2785  for (depth=1; colors != 0; depth++)
2786  colors>>=2;
2787  if (quantize_info->dither != MagickFalse)
2788  depth--;
2789  }
2790  /*
2791  Initialize color cube.
2792  */
2793  cube_info=GetQCubeInfo(quantize_info,depth,maximum_colors);
2794  if (cube_info == (QCubeInfo *) NULL)
2795  {
2796  (void) ThrowMagickException(&images->exception,GetMagickModule(),
2797  ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
2798  return(MagickFalse);
2799  }
2800  number_images=GetImageListLength(images);
2801  image=images;
2802  for (i=0; image != (Image *) NULL; i++)
2803  {
2804  progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
2805  image->client_data);
2806  status=ClassifyImageColors(cube_info,image,&image->exception);
2807  if (status == MagickFalse)
2808  break;
2809  (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
2810  proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
2811  number_images);
2812  if (proceed == MagickFalse)
2813  break;
2814  image=GetNextImageInList(image);
2815  }
2816  if (status != MagickFalse)
2817  {
2818  /*
2819  Reduce the number of colors in an image sequence.
2820  */
2821  ReduceImageColors(images,cube_info);
2822  image=images;
2823  for (i=0; image != (Image *) NULL; i++)
2824  {
2825  progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor)
2826  NULL,image->client_data);
2827  status=AssignImageColors(image,cube_info);
2828  if (status == MagickFalse)
2829  break;
2830  (void) SetImageProgressMonitor(image,progress_monitor,
2831  image->client_data);
2832  proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
2833  number_images);
2834  if (proceed == MagickFalse)
2835  break;
2836  image=GetNextImageInList(image);
2837  }
2838  }
2839  DestroyQCubeInfo(cube_info);
2840  return(status);
2841 }
2842 
2843 /*
2844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845 % %
2846 % %
2847 % %
2848 + Q u a n t i z e E r r o r F l a t t e n %
2849 % %
2850 % %
2851 % %
2852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853 %
2854 % QuantizeErrorFlatten() traverses the color cube and flattens the quantization
2855 % error into a sorted 1D array. This accelerates the color reduction process.
2856 %
2857 % Contributed by Yoya.
2858 %
2859 % The format of the QuantizeErrorFlatten method is:
2860 %
2861 % size_t QuantizeErrorFlatten(const QCubeInfo *cube_info,
2862 % const QNodeInfo *node_info,const ssize_t offset,
2863 % MagickRealType *quantize_error)
2864 %
2865 % A description of each parameter follows.
2866 %
2867 % o cube_info: A pointer to the Cube structure.
2868 %
2869 % o node_info: pointer to node in color cube tree that is current pointer.
2870 %
2871 % o offset: quantize error offset.
2872 %
2873 % o quantize_error: the quantization error vector.
2874 %
2875 */
2876 static size_t QuantizeErrorFlatten(const QCubeInfo *cube_info,
2877  const QNodeInfo *node_info,const ssize_t offset,
2878  MagickRealType *quantize_error)
2879 {
2880  size_t
2881  n,
2882  number_children;
2883 
2884  ssize_t
2885  i;
2886 
2887  if (offset >= (ssize_t) cube_info->nodes)
2888  return(0);
2889  quantize_error[offset]=node_info->quantize_error;
2890  n=1;
2891  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2892  for (i=0; i < (ssize_t) number_children ; i++)
2893  if (node_info->child[i] != (QNodeInfo *) NULL)
2894  n+=QuantizeErrorFlatten(cube_info,node_info->child[i],offset+n,
2895  quantize_error);
2896  return(n);
2897 }
2898 
2899 /*
2900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2901 % %
2902 % %
2903 % %
2904 + R e d u c e %
2905 % %
2906 % %
2907 % %
2908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909 %
2910 % Reduce() traverses the color cube tree and prunes any node whose
2911 % quantization error falls below a particular threshold.
2912 %
2913 % The format of the Reduce method is:
2914 %
2915 % Reduce(QCubeInfo *cube_info,const QNodeInfo *node_info)
2916 %
2917 % A description of each parameter follows.
2918 %
2919 % o cube_info: A pointer to the Cube structure.
2920 %
2921 % o node_info: pointer to node in color cube tree that is to be pruned.
2922 %
2923 */
2924 static void Reduce(QCubeInfo *cube_info,const QNodeInfo *node_info)
2925 {
2926  size_t
2927  number_children;
2928 
2929  ssize_t
2930  i;
2931 
2932  /*
2933  Traverse any children.
2934  */
2935  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
2936  for (i=0; i < (ssize_t) number_children; i++)
2937  if (node_info->child[i] != (QNodeInfo *) NULL)
2938  Reduce(cube_info,node_info->child[i]);
2939  if (node_info->quantize_error <= cube_info->pruning_threshold)
2940  PruneChild(cube_info,node_info);
2941  else
2942  {
2943  /*
2944  Find minimum pruning threshold.
2945  */
2946  if (node_info->number_unique > 0)
2947  cube_info->colors++;
2948  if (node_info->quantize_error < cube_info->next_threshold)
2949  cube_info->next_threshold=node_info->quantize_error;
2950  }
2951 }
2952 
2953 /*
2954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955 % %
2956 % %
2957 % %
2958 + R e d u c e I m a g e C o l o r s %
2959 % %
2960 % %
2961 % %
2962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963 %
2964 % ReduceImageColors() repeatedly prunes the tree until the number of nodes
2965 % with n2 > 0 is less than or equal to the maximum number of colors allowed
2966 % in the output image. On any given iteration over the tree, it selects
2967 % those nodes whose E value is minimal for pruning and merges their
2968 % color statistics upward. It uses a pruning threshold, Ep, to govern
2969 % node selection as follows:
2970 %
2971 % Ep = 0
2972 % while number of nodes with (n2 > 0) > required maximum number of colors
2973 % prune all nodes such that E <= Ep
2974 % Set Ep to minimum E in remaining nodes
2975 %
2976 % This has the effect of minimizing any quantization error when merging
2977 % two nodes together.
2978 %
2979 % When a node to be pruned has offspring, the pruning procedure invokes
2980 % itself recursively in order to prune the tree from the leaves upward.
2981 % n2, Sr, Sg, and Sb in a node being pruned are always added to the
2982 % corresponding data in that node's parent. This retains the pruned
2983 % node's color characteristics for later averaging.
2984 %
2985 % For each node, n2 pixels exist for which that node represents the
2986 % smallest volume in RGB space containing those pixel's colors. When n2
2987 % > 0 the node will uniquely define a color in the output image. At the
2988 % beginning of reduction, n2 = 0 for all nodes except a the leaves of
2989 % the tree which represent colors present in the input image.
2990 %
2991 % The other pixel count, n1, indicates the total number of colors
2992 % within the cubic volume which the node represents. This includes n1 -
2993 % n2 pixels whose colors should be defined by nodes at a lower level in
2994 % the tree.
2995 %
2996 % The format of the ReduceImageColors method is:
2997 %
2998 % ReduceImageColors(const Image *image,QCubeInfo *cube_info)
2999 %
3000 % A description of each parameter follows.
3001 %
3002 % o image: the image.
3003 %
3004 % o cube_info: A pointer to the Cube structure.
3005 %
3006 */
3007 
3008 static int MagickRealTypeCompare(const void *error_p,const void *error_q)
3009 {
3010  MagickRealType
3011  *p,
3012  *q;
3013 
3014  p=(MagickRealType *) error_p;
3015  q=(MagickRealType *) error_q;
3016  if (*p > *q)
3017  return(1);
3018  if (fabs((double) (*q-*p)) <= MagickEpsilon)
3019  return(0);
3020  return(-1);
3021 }
3022 
3023 static void ReduceImageColors(const Image *image,QCubeInfo *cube_info)
3024 {
3025 #define ReduceImageTag "Reduce/Image"
3026 
3027  MagickBooleanType
3028  proceed;
3029 
3030  MagickOffsetType
3031  offset;
3032 
3033  size_t
3034  span;
3035 
3036  cube_info->next_threshold=0.0;
3037  if (cube_info->colors > cube_info->maximum_colors)
3038  {
3039  MagickRealType
3040  *quantize_error;
3041 
3042  /*
3043  Enable rapid reduction of the number of unique colors.
3044  */
3045  quantize_error=(MagickRealType *) AcquireQuantumMemory(cube_info->nodes,
3046  sizeof(*quantize_error));
3047  if (quantize_error != (MagickRealType *) NULL)
3048  {
3049  (void) QuantizeErrorFlatten(cube_info,cube_info->root,0,
3050  quantize_error);
3051  qsort(quantize_error,cube_info->nodes,sizeof(MagickRealType),
3052  MagickRealTypeCompare);
3053  if (cube_info->nodes > (110*(cube_info->maximum_colors+1)/100))
3054  cube_info->next_threshold=quantize_error[cube_info->nodes-110*
3055  (cube_info->maximum_colors+1)/100];
3056  quantize_error=(MagickRealType *) RelinquishMagickMemory(
3057  quantize_error);
3058  }
3059  }
3060  for (span=cube_info->colors; cube_info->colors > cube_info->maximum_colors; )
3061  {
3062  cube_info->pruning_threshold=cube_info->next_threshold;
3063  cube_info->next_threshold=cube_info->root->quantize_error-1;
3064  cube_info->colors=0;
3065  Reduce(cube_info,cube_info->root);
3066  offset=(MagickOffsetType) span-cube_info->colors;
3067  proceed=SetImageProgress(image,ReduceImageTag,offset,span-
3068  cube_info->maximum_colors+1);
3069  if (proceed == MagickFalse)
3070  break;
3071  }
3072 }
3073 
3074 /*
3075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3076 % %
3077 % %
3078 % %
3079 % R e m a p I m a g e %
3080 % %
3081 % %
3082 % %
3083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3084 %
3085 % RemapImage() replaces the colors of an image with the closest color from
3086 % a reference image.
3087 %
3088 % The format of the RemapImage method is:
3089 %
3090 % MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
3091 % Image *image,const Image *remap_image)
3092 %
3093 % A description of each parameter follows:
3094 %
3095 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
3096 %
3097 % o image: the image.
3098 %
3099 % o remap_image: the reference image.
3100 %
3101 */
3102 MagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
3103  Image *image,const Image *remap_image)
3104 {
3105  MagickBooleanType
3106  status;
3107 
3108  QCubeInfo
3109  *cube_info;
3110 
3111  /*
3112  Initialize color cube.
3113  */
3114  assert(image != (Image *) NULL);
3115  assert(image->signature == MagickCoreSignature);
3116  if (IsEventLogging() != MagickFalse)
3117  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3118  assert(remap_image != (Image *) NULL);
3119  assert(remap_image->signature == MagickCoreSignature);
3120  cube_info=GetQCubeInfo(quantize_info,MaxTreeDepth,MaxColormapSize);
3121  if (cube_info == (QCubeInfo *) NULL)
3122  ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
3123  image->filename);
3124  cube_info->quantize_info->colorspace=remap_image->colorspace;
3125  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
3126  if (status != MagickFalse)
3127  {
3128  /*
3129  Classify image colors from the reference image.
3130  */
3131  cube_info->quantize_info->number_colors=cube_info->colors;
3132  if (cube_info->colors > cube_info->maximum_colors)
3133  ReduceImageColors(image,cube_info);
3134  status=AssignImageColors(image,cube_info);
3135  }
3136  DestroyQCubeInfo(cube_info);
3137  return(status);
3138 }
3139 
3140 /*
3141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3142 % %
3143 % %
3144 % %
3145 % R e m a p I m a g e s %
3146 % %
3147 % %
3148 % %
3149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3150 %
3151 % RemapImages() replaces the colors of a sequence of images with the
3152 % closest color from a reference image.
3153 %
3154 % The format of the RemapImage method is:
3155 %
3156 % MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
3157 % Image *images,Image *remap_image)
3158 %
3159 % A description of each parameter follows:
3160 %
3161 % o quantize_info: Specifies a pointer to an QuantizeInfo structure.
3162 %
3163 % o images: the image sequence.
3164 %
3165 % o remap_image: the reference image.
3166 %
3167 */
3168 MagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
3169  Image *images,const Image *remap_image)
3170 {
3171  Image
3172  *image;
3173 
3174  MagickBooleanType
3175  status;
3176 
3177  QCubeInfo
3178  *cube_info;
3179 
3180  assert(images != (Image *) NULL);
3181  assert(images->signature == MagickCoreSignature);
3182  if (IsEventLogging() != MagickFalse)
3183  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3184  image=images;
3185  if (remap_image == (Image *) NULL)
3186  {
3187  /*
3188  Create a global colormap for an image sequence.
3189  */
3190  status=QuantizeImages(quantize_info,images);
3191  return(status);
3192  }
3193  /*
3194  Classify image colors from the reference image.
3195  */
3196  cube_info=GetQCubeInfo(quantize_info,MaxTreeDepth,
3197  quantize_info->number_colors);
3198  if (cube_info == (QCubeInfo *) NULL)
3199  ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
3200  image->filename);
3201  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
3202  if (status != MagickFalse)
3203  {
3204  /*
3205  Classify image colors from the reference image.
3206  */
3207  cube_info->quantize_info->number_colors=cube_info->colors;
3208  image=images;
3209  for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
3210  {
3211  status=AssignImageColors(image,cube_info);
3212  if (status == MagickFalse)
3213  break;
3214  }
3215  }
3216  DestroyQCubeInfo(cube_info);
3217  return(status);
3218 }
3219 
3220 /*
3221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3222 % %
3223 % %
3224 % %
3225 % S e t G r a y s c a l e I m a g e %
3226 % %
3227 % %
3228 % %
3229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3230 %
3231 % SetGrayscaleImage() converts an image to a PseudoClass grayscale image.
3232 %
3233 % The format of the SetGrayscaleImage method is:
3234 %
3235 % MagickBooleanType SetGrayscaleImage(Image *image)
3236 %
3237 % A description of each parameter follows:
3238 %
3239 % o image: The image.
3240 %
3241 */
3242 
3243 #if defined(__cplusplus) || defined(c_plusplus)
3244 extern "C" {
3245 #endif
3246 
3247 static int IntensityCompare(const void *x,const void *y)
3248 {
3249  double
3250  intensity;
3251 
3252  PixelPacket
3253  *color_1,
3254  *color_2;
3255 
3256  color_1=(PixelPacket *) x;
3257  color_2=(PixelPacket *) y;
3258  intensity=PixelPacketIntensity(color_1)-PixelPacketIntensity(color_2);
3259  if (intensity < (double) INT_MIN)
3260  intensity=(double) INT_MIN;
3261  if (intensity > (double) INT_MAX)
3262  intensity=(double) INT_MAX;
3263  return((int) intensity);
3264 }
3265 
3266 #if defined(__cplusplus) || defined(c_plusplus)
3267 }
3268 #endif
3269 
3270 static MagickBooleanType SetGrayscaleImage(Image *image)
3271 {
3272  CacheView
3273  *image_view;
3274 
3276  *exception;
3277 
3278  MagickBooleanType
3279  status;
3280 
3281  PixelPacket
3282  *colormap;
3283 
3284  size_t
3285  extent;
3286 
3287  ssize_t
3288  *colormap_index,
3289  i,
3290  j,
3291  y;
3292 
3293  assert(image != (Image *) NULL);
3294  assert(image->signature == MagickCoreSignature);
3295  exception=(&image->exception);
3296  if (image->type != GrayscaleType)
3297  (void) TransformImageColorspace(image,GRAYColorspace);
3298  extent=MagickMax(image->colors+1,MagickMax(MaxColormapSize,MaxMap+1));
3299  colormap_index=(ssize_t *) AcquireQuantumMemory(extent,
3300  sizeof(*colormap_index));
3301  if (colormap_index == (ssize_t *) NULL)
3302  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3303  image->filename);
3304  if (image->storage_class != PseudoClass)
3305  {
3306  (void) memset(colormap_index,(-1),extent*sizeof(*colormap_index));
3307  if (AcquireImageColormap(image,MaxColormapSize) == MagickFalse)
3308  {
3309  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
3310  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3311  image->filename);
3312  }
3313  image->colors=0;
3314  status=MagickTrue;
3315  image_view=AcquireAuthenticCacheView(image,exception);
3316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3317  #pragma omp parallel for schedule(static) shared(status) \
3318  magick_number_threads(image,image,image->rows,1)
3319 #endif
3320  for (y=0; y < (ssize_t) image->rows; y++)
3321  {
3322  IndexPacket
3323  *magick_restrict indexes;
3324 
3325  PixelPacket
3326  *magick_restrict q;
3327 
3328  ssize_t
3329  x;
3330 
3331  if (status == MagickFalse)
3332  continue;
3333  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
3334  exception);
3335  if (q == (PixelPacket *) NULL)
3336  {
3337  status=MagickFalse;
3338  continue;
3339  }
3340  indexes=GetCacheViewAuthenticIndexQueue(image_view);
3341  for (x=0; x < (ssize_t) image->columns; x++)
3342  {
3343  size_t
3344  intensity;
3345 
3346  intensity=ScaleQuantumToMap(GetPixelRed(q));
3347  if (colormap_index[intensity] < 0)
3348  {
3349 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3350  #pragma omp critical (MagickCore_SetGrayscaleImage)
3351 #endif
3352  if (colormap_index[intensity] < 0)
3353  {
3354  colormap_index[intensity]=(ssize_t) image->colors;
3355  image->colormap[image->colors].red=GetPixelRed(q);
3356  image->colormap[image->colors].green=GetPixelGreen(q);
3357  image->colormap[image->colors].blue=GetPixelBlue(q);
3358  image->colors++;
3359  }
3360  }
3361  SetPixelIndex(indexes+x,colormap_index[intensity]);
3362  q++;
3363  }
3364  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3365  status=MagickFalse;
3366  }
3367  image_view=DestroyCacheView(image_view);
3368  }
3369  (void) memset(colormap_index,0,extent*sizeof(*colormap_index));
3370  for (i=0; i < (ssize_t) image->colors; i++)
3371  image->colormap[i].opacity=(Quantum) i;
3372  qsort((void *) image->colormap,image->colors,sizeof(PixelPacket),
3373  IntensityCompare);
3374  colormap=(PixelPacket *) AcquireQuantumMemory(image->colors,
3375  sizeof(*colormap));
3376  if (colormap == (PixelPacket *) NULL)
3377  {
3378  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
3379  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3380  image->filename);
3381  }
3382  j=0;
3383  colormap[j]=image->colormap[0];
3384  for (i=0; i < (ssize_t) image->colors; i++)
3385  {
3386  if (IsSameColor(image,&colormap[j],&image->colormap[i]) == MagickFalse)
3387  {
3388  j++;
3389  colormap[j]=image->colormap[i];
3390  }
3391  colormap_index[(ssize_t) image->colormap[i].opacity]=j;
3392  }
3393  image->colors=(size_t) (j+1);
3394  image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
3395  image->colormap=colormap;
3396  status=MagickTrue;
3397  image_view=AcquireAuthenticCacheView(image,exception);
3398 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3399  #pragma omp parallel for schedule(static) shared(status) \
3400  magick_number_threads(image,image,image->rows,1)
3401 #endif
3402  for (y=0; y < (ssize_t) image->rows; y++)
3403  {
3404  IndexPacket
3405  *magick_restrict indexes;
3406 
3407  const PixelPacket
3408  *magick_restrict q;
3409 
3410  ssize_t
3411  x;
3412 
3413  if (status == MagickFalse)
3414  continue;
3415  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3416  if (q == (PixelPacket *) NULL)
3417  {
3418  status=MagickFalse;
3419  continue;
3420  }
3421  indexes=GetCacheViewAuthenticIndexQueue(image_view);
3422  for (x=0; x < (ssize_t) image->columns; x++)
3423  SetPixelIndex(indexes+x,colormap_index[ScaleQuantumToMap(GetPixelIndex(
3424  indexes+x))]);
3425  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3426  status=MagickFalse;
3427  }
3428  image_view=DestroyCacheView(image_view);
3429  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
3430  image->type=GrayscaleType;
3431  if (SetImageMonochrome(image,&image->exception) != MagickFalse)
3432  image->type=BilevelType;
3433  return(status);
3434 }
Definition: image.h:133