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