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