]> granicus.if.org Git - imagemagick/blob - MagickCore/histogram.c
(no commit message)
[imagemagick] / MagickCore / histogram.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %      H   H   IIIII   SSSSS  TTTTT   OOO    GGGG  RRRR    AAA   M   M        %
7 %      H   H     I     SS       T    O   O  G      R   R  A   A  MM MM        %
8 %      HHHHH     I      SSS     T    O   O  G  GG  RRRR   AAAAA  M M M        %
9 %      H   H     I        SS    T    O   O  G   G  R R    A   A  M   M        %
10 %      H   H   IIIII   SSSSS    T     OOO    GGG   R  R   A   A  M   M        %
11 %                                                                             %
12 %                                                                             %
13 %                        MagickCore Histogram Methods                         %
14 %                                                                             %
15 %                              Software Design                                %
16 %                              Anthony Thyssen                                %
17 %                               Fred Weinhaus                                 %
18 %                                August 2009                                  %
19 %                                                                             %
20 %                                                                             %
21 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
22 %  dedicated to making software imaging solutions freely available.           %
23 %                                                                             %
24 %  You may not use this file except in compliance with the License.  You may  %
25 %  obtain a copy of the License at                                            %
26 %                                                                             %
27 %    http://www.imagemagick.org/script/license.php                            %
28 %                                                                             %
29 %  Unless required by applicable law or agreed to in writing, software        %
30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32 %  See the License for the specific language governing permissions and        %
33 %  limitations under the License.                                             %
34 %                                                                             %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/cache-view.h"
45 #include "MagickCore/color-private.h"
46 #include "MagickCore/enhance.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/hashmap.h"
50 #include "MagickCore/histogram.h"
51 #include "MagickCore/image.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/pixel-accessor.h"
56 #include "MagickCore/prepress.h"
57 #include "MagickCore/quantize.h"
58 #include "MagickCore/registry.h"
59 #include "MagickCore/semaphore.h"
60 #include "MagickCore/splay-tree.h"
61 #include "MagickCore/statistic.h"
62 #include "MagickCore/string_.h"
63 \f
64 /*
65   Define declarations.
66 */
67 #define MaxTreeDepth  8
68 #define NodesInAList  1536
69 \f
70 /*
71   Typedef declarations.
72 */
73 typedef struct _NodeInfo
74 {
75   struct _NodeInfo
76     *child[16];
77
78   PixelInfo
79     *list;
80
81   MagickSizeType
82     number_unique;
83
84   size_t
85     level;
86 } NodeInfo;
87
88 typedef struct _Nodes
89 {
90   NodeInfo
91     nodes[NodesInAList];
92
93   struct _Nodes
94     *next;
95 } Nodes;
96
97 typedef struct _CubeInfo
98 {
99   NodeInfo
100     *root;
101
102   ssize_t
103     x;
104
105   MagickOffsetType
106     progress;
107
108   size_t
109     colors,
110     free_nodes;
111
112   NodeInfo
113     *node_info;
114
115   Nodes
116     *node_queue;
117 } CubeInfo;
118 \f
119 /*
120   Forward declarations.
121 */
122 static CubeInfo
123   *GetCubeInfo(void);
124
125 static NodeInfo
126   *GetNodeInfo(CubeInfo *,const size_t);
127
128 static void
129   DestroyColorCube(const Image *,NodeInfo *);
130 \f
131 /*
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 %                                                                             %
134 %                                                                             %
135 %                                                                             %
136 +   C l a s s i f y I m a g e C o l o r s                                     %
137 %                                                                             %
138 %                                                                             %
139 %                                                                             %
140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 %
142 %  ClassifyImageColors() builds a populated CubeInfo tree for the specified
143 %  image.  The returned tree should be deallocated using DestroyCubeInfo()
144 %  once it is no longer needed.
145 %
146 %  The format of the ClassifyImageColors() method is:
147 %
148 %      CubeInfo *ClassifyImageColors(const Image *image,
149 %        ExceptionInfo *exception)
150 %
151 %  A description of each parameter follows.
152 %
153 %    o image: the image.
154 %
155 %    o exception: return any errors or warnings in this structure.
156 %
157 */
158
159 static inline size_t ColorToNodeId(const Image *image,
160   const PixelInfo *pixel,size_t index)
161 {
162   size_t
163     id;
164
165   id=(size_t) (
166     ((ScaleQuantumToChar(ClampToQuantum(pixel->red)) >> index) & 0x01) |
167     ((ScaleQuantumToChar(ClampToQuantum(pixel->green)) >> index) & 0x01) << 1 |
168     ((ScaleQuantumToChar(ClampToQuantum(pixel->blue)) >> index) & 0x01) << 2);
169   if (image->alpha_trait == BlendPixelTrait)
170     id|=((ScaleQuantumToChar(ClampToQuantum(pixel->alpha)) >> index) &
171       0x01) << 3;
172   return(id);
173 }
174
175 static CubeInfo *ClassifyImageColors(const Image *image,
176   ExceptionInfo *exception)
177 {
178 #define EvaluateImageTag  "  Compute image colors...  "
179
180   CacheView
181     *image_view;
182
183   CubeInfo
184     *cube_info;
185
186   MagickBooleanType
187     proceed;
188
189   PixelInfo
190     pixel,
191     target;
192
193   NodeInfo
194     *node_info;
195
196   register const Quantum
197     *p;
198
199   register size_t
200     id,
201     index,
202     level;
203
204   register ssize_t
205     i,
206     x;
207
208   ssize_t
209     y;
210
211   /*
212     Initialize color description tree.
213   */
214   assert(image != (const Image *) NULL);
215   assert(image->signature == MagickSignature);
216   if (image->debug != MagickFalse)
217     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
218   cube_info=GetCubeInfo();
219   if (cube_info == (CubeInfo *) NULL)
220     {
221       (void) ThrowMagickException(exception,GetMagickModule(),
222         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
223       return(cube_info);
224     }
225   GetPixelInfo(image,&pixel);
226   GetPixelInfo(image,&target);
227   image_view=AcquireVirtualCacheView(image,exception);
228   for (y=0; y < (ssize_t) image->rows; y++)
229   {
230     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
231     if (p == (const Quantum *) NULL)
232       break;
233     for (x=0; x < (ssize_t) image->columns; x++)
234     {
235       /*
236         Start at the root and proceed level by level.
237       */
238       node_info=cube_info->root;
239       index=MaxTreeDepth-1;
240       for (level=1; level < MaxTreeDepth; level++)
241       {
242         GetPixelInfoPixel(image,p,&pixel);
243         id=ColorToNodeId(image,&pixel,index);
244         if (node_info->child[id] == (NodeInfo *) NULL)
245           {
246             node_info->child[id]=GetNodeInfo(cube_info,level);
247             if (node_info->child[id] == (NodeInfo *) NULL)
248               {
249                 (void) ThrowMagickException(exception,GetMagickModule(),
250                   ResourceLimitError,"MemoryAllocationFailed","'%s'",
251                   image->filename);
252                 return(0);
253               }
254           }
255         node_info=node_info->child[id];
256         index--;
257       }
258       for (i=0; i < (ssize_t) node_info->number_unique; i++)
259       {
260         target=node_info->list[i];
261         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
262           break;
263       }
264       if (i < (ssize_t) node_info->number_unique)
265         node_info->list[i].count++;
266       else
267         {
268           if (node_info->number_unique == 0)
269             node_info->list=(PixelInfo *) AcquireMagickMemory(
270               sizeof(*node_info->list));
271           else
272             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
273               (size_t) (i+1),sizeof(*node_info->list));
274           if (node_info->list == (PixelInfo *) NULL)
275             {
276               (void) ThrowMagickException(exception,GetMagickModule(),
277                 ResourceLimitError,"MemoryAllocationFailed","'%s'",
278                 image->filename);
279               return(0);
280             }
281           node_info->list[i]=pixel;
282           node_info->list[i].red=(double) GetPixelRed(image,p);
283           node_info->list[i].green=(double) GetPixelGreen(image,p);
284           node_info->list[i].blue=(double) GetPixelBlue(image,p);
285           if (image->colorspace == CMYKColorspace)
286             node_info->list[i].black=(double) GetPixelBlack(image,p);
287           node_info->list[i].alpha=(double) GetPixelAlpha(image,p);
288           node_info->list[i].count=1;
289           node_info->number_unique++;
290           cube_info->colors++;
291         }
292       p+=GetPixelChannels(image);
293     }
294     proceed=SetImageProgress(image,EvaluateImageTag,(MagickOffsetType) y,
295       image->rows);
296     if (proceed == MagickFalse)
297       break;
298   }
299   image_view=DestroyCacheView(image_view);
300   return(cube_info);
301 }
302 \f
303 /*
304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305 %                                                                             %
306 %                                                                             %
307 %                                                                             %
308 +   D e f i n e I m a g e H i s t o g r a m                                   %
309 %                                                                             %
310 %                                                                             %
311 %                                                                             %
312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 %
314 %  DefineImageHistogram() traverses the color cube tree and notes each colormap
315 %  entry.  A colormap entry is any node in the color cube tree where the
316 %  of unique colors is not zero.
317 %
318 %  The format of the DefineImageHistogram method is:
319 %
320 %      DefineImageHistogram(const Image *image,NodeInfo *node_info,
321 %        PixelInfo **unique_colors)
322 %
323 %  A description of each parameter follows.
324 %
325 %    o image: the image.
326 %
327 %    o node_info: the address of a structure of type NodeInfo which points to a
328 %      node in the color cube tree that is to be pruned.
329 %
330 %    o histogram: the image histogram.
331 %
332 */
333 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
334   PixelInfo **histogram)
335 {
336   register ssize_t
337     i;
338
339   size_t
340     number_children;
341
342   /*
343     Traverse any children.
344   */
345   number_children=image->alpha_trait != BlendPixelTrait ? 8UL : 16UL;
346   for (i=0; i < (ssize_t) number_children; i++)
347     if (node_info->child[i] != (NodeInfo *) NULL)
348       DefineImageHistogram(image,node_info->child[i],histogram);
349   if (node_info->level == (MaxTreeDepth-1))
350     {
351       register PixelInfo
352         *p;
353
354       p=node_info->list;
355       for (i=0; i < (ssize_t) node_info->number_unique; i++)
356       {
357         **histogram=(*p);
358         (*histogram)++;
359         p++;
360       }
361     }
362 }
363 \f
364 /*
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 %                                                                             %
367 %                                                                             %
368 %                                                                             %
369 +   D e s t r o y C u b e I n f o                                             %
370 %                                                                             %
371 %                                                                             %
372 %                                                                             %
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 %
375 %  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
376 %
377 %  The format of the DestroyCubeInfo method is:
378 %
379 %      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
380 %
381 %  A description of each parameter follows:
382 %
383 %    o image: the image.
384 %
385 %    o cube_info: the address of a structure of type CubeInfo.
386 %
387 */
388 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
389 {
390   register Nodes
391     *nodes;
392
393   /*
394     Release color cube tree storage.
395   */
396   DestroyColorCube(image,cube_info->root);
397   do
398   {
399     nodes=cube_info->node_queue->next;
400     cube_info->node_queue=(Nodes *)
401       RelinquishMagickMemory(cube_info->node_queue);
402     cube_info->node_queue=nodes;
403   } while (cube_info->node_queue != (Nodes *) NULL);
404   return((CubeInfo *) RelinquishMagickMemory(cube_info));
405 }
406 \f
407 /*
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409 %                                                                             %
410 %                                                                             %
411 %                                                                             %
412 +  D e s t r o y C o l o r C u b e                                            %
413 %                                                                             %
414 %                                                                             %
415 %                                                                             %
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 %
418 %  DestroyColorCube() traverses the color cube tree and frees the list of
419 %  unique colors.
420 %
421 %  The format of the DestroyColorCube method is:
422 %
423 %      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
424 %
425 %  A description of each parameter follows.
426 %
427 %    o image: the image.
428 %
429 %    o node_info: the address of a structure of type NodeInfo which points to a
430 %      node in the color cube tree that is to be pruned.
431 %
432 */
433 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
434 {
435   register ssize_t
436     i;
437
438   size_t
439     number_children;
440
441   /*
442     Traverse any children.
443   */
444   number_children=image->alpha_trait != BlendPixelTrait ? 8UL : 16UL;
445   for (i=0; i < (ssize_t) number_children; i++)
446     if (node_info->child[i] != (NodeInfo *) NULL)
447       DestroyColorCube(image,node_info->child[i]);
448   if (node_info->list != (PixelInfo *) NULL)
449     node_info->list=(PixelInfo *) RelinquishMagickMemory(node_info->list);
450 }
451 \f
452 /*
453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 %                                                                             %
455 %                                                                             %
456 %                                                                             %
457 +   G e t C u b e I n f o                                                     %
458 %                                                                             %
459 %                                                                             %
460 %                                                                             %
461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462 %
463 %  GetCubeInfo() initializes the CubeInfo data structure.
464 %
465 %  The format of the GetCubeInfo method is:
466 %
467 %      cube_info=GetCubeInfo()
468 %
469 %  A description of each parameter follows.
470 %
471 %    o cube_info: A pointer to the Cube structure.
472 %
473 */
474 static CubeInfo *GetCubeInfo(void)
475 {
476   CubeInfo
477     *cube_info;
478
479   /*
480     Initialize tree to describe color cube.
481   */
482   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
483   if (cube_info == (CubeInfo *) NULL)
484     return((CubeInfo *) NULL);
485   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
486   /*
487     Initialize root node.
488   */
489   cube_info->root=GetNodeInfo(cube_info,0);
490   if (cube_info->root == (NodeInfo *) NULL)
491     return((CubeInfo *) NULL);
492   return(cube_info);
493 }
494 \f
495 /*
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 %                                                                             %
498 %                                                                             %
499 %                                                                             %
500 %  G e t I m a g e H i s t o g r a m                                          %
501 %                                                                             %
502 %                                                                             %
503 %                                                                             %
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
505 %
506 %  GetImageHistogram() returns the unique colors in an image.
507 %
508 %  The format of the GetImageHistogram method is:
509 %
510 %      size_t GetImageHistogram(const Image *image,
511 %        size_t *number_colors,ExceptionInfo *exception)
512 %
513 %  A description of each parameter follows.
514 %
515 %    o image: the image.
516 %
517 %    o file:  Write a histogram of the color distribution to this file handle.
518 %
519 %    o exception: return any errors or warnings in this structure.
520 %
521 */
522 MagickExport PixelInfo *GetImageHistogram(const Image *image,
523   size_t *number_colors,ExceptionInfo *exception)
524 {
525   PixelInfo
526     *histogram;
527
528   CubeInfo
529     *cube_info;
530
531   *number_colors=0;
532   histogram=(PixelInfo *) NULL;
533   cube_info=ClassifyImageColors(image,exception);
534   if (cube_info != (CubeInfo *) NULL)
535     {
536       histogram=(PixelInfo *) AcquireQuantumMemory((size_t) cube_info->colors,
537         sizeof(*histogram));
538       if (histogram == (PixelInfo *) NULL)
539         (void) ThrowMagickException(exception,GetMagickModule(),
540           ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
541       else
542         {
543           PixelInfo
544             *root;
545
546           *number_colors=cube_info->colors;
547           root=histogram;
548           DefineImageHistogram(image,cube_info->root,&root);
549         }
550     }
551   cube_info=DestroyCubeInfo(image,cube_info);
552   return(histogram);
553 }
554 \f
555 /*
556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557 %                                                                             %
558 %                                                                             %
559 %                                                                             %
560 +  G e t N o d e I n f o                                                      %
561 %                                                                             %
562 %                                                                             %
563 %                                                                             %
564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 %
566 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
567 %  presets all fields to zero.
568 %
569 %  The format of the GetNodeInfo method is:
570 %
571 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
572 %
573 %  A description of each parameter follows.
574 %
575 %    o cube_info: A pointer to the CubeInfo structure.
576 %
577 %    o level: Specifies the level in the storage_class the node resides.
578 %
579 */
580 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
581 {
582   NodeInfo
583     *node_info;
584
585   if (cube_info->free_nodes == 0)
586     {
587       Nodes
588         *nodes;
589
590       /*
591         Allocate a new nodes of nodes.
592       */
593       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
594       if (nodes == (Nodes *) NULL)
595         return((NodeInfo *) NULL);
596       nodes->next=cube_info->node_queue;
597       cube_info->node_queue=nodes;
598       cube_info->node_info=nodes->nodes;
599       cube_info->free_nodes=NodesInAList;
600     }
601   cube_info->free_nodes--;
602   node_info=cube_info->node_info++;
603   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
604   node_info->level=level;
605   return(node_info);
606 }
607 \f
608 /*
609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 %                                                                             %
611 %                                                                             %
612 %                                                                             %
613 %  I s H i s t o g r a m I m a g e                                            %
614 %                                                                             %
615 %                                                                             %
616 %                                                                             %
617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
618 %
619 %  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
620 %  less.
621 %
622 %  The format of the IsHistogramImage method is:
623 %
624 %      MagickBooleanType IsHistogramImage(const Image *image,
625 %        ExceptionInfo *exception)
626 %
627 %  A description of each parameter follows.
628 %
629 %    o image: the image.
630 %
631 %    o exception: return any errors or warnings in this structure.
632 %
633 */
634 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
635   ExceptionInfo *exception)
636 {
637 #define MaximumUniqueColors  1024
638
639   CacheView
640     *image_view;
641
642   CubeInfo
643     *cube_info;
644
645   PixelInfo
646     pixel,
647     target;
648
649   register const Quantum
650     *p;
651
652   register ssize_t
653     x;
654
655   register NodeInfo
656     *node_info;
657
658   register ssize_t
659     i;
660
661   size_t
662     id,
663     index,
664     level;
665
666   ssize_t
667     y;
668
669   assert(image != (Image *) NULL);
670   assert(image->signature == MagickSignature);
671   if (image->debug != MagickFalse)
672     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
673   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
674     return(MagickTrue);
675   if (image->storage_class == PseudoClass)
676     return(MagickFalse);
677   /*
678     Initialize color description tree.
679   */
680   cube_info=GetCubeInfo();
681   if (cube_info == (CubeInfo *) NULL)
682     {
683       (void) ThrowMagickException(exception,GetMagickModule(),
684         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
685       return(MagickFalse);
686     }
687   GetPixelInfo(image,&pixel);
688   GetPixelInfo(image,&target);
689   image_view=AcquireVirtualCacheView(image,exception);
690   for (y=0; y < (ssize_t) image->rows; y++)
691   {
692     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
693     if (p == (const Quantum *) NULL)
694       break;
695     for (x=0; x < (ssize_t) image->columns; x++)
696     {
697       /*
698         Start at the root and proceed level by level.
699       */
700       node_info=cube_info->root;
701       index=MaxTreeDepth-1;
702       for (level=1; level < MaxTreeDepth; level++)
703       {
704         GetPixelInfoPixel(image,p,&pixel);
705         id=ColorToNodeId(image,&pixel,index);
706         if (node_info->child[id] == (NodeInfo *) NULL)
707           {
708             node_info->child[id]=GetNodeInfo(cube_info,level);
709             if (node_info->child[id] == (NodeInfo *) NULL)
710               {
711                 (void) ThrowMagickException(exception,GetMagickModule(),
712                   ResourceLimitError,"MemoryAllocationFailed","'%s'",
713                   image->filename);
714                 break;
715               }
716           }
717         node_info=node_info->child[id];
718         index--;
719       }
720       if (level < MaxTreeDepth)
721         break;
722       for (i=0; i < (ssize_t) node_info->number_unique; i++)
723       {
724         target=node_info->list[i];
725         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
726           break;
727       }
728       if (i < (ssize_t) node_info->number_unique)
729         node_info->list[i].count++;
730       else
731         {
732           /*
733             Add this unique color to the color list.
734           */
735           if (node_info->number_unique == 0)
736             node_info->list=(PixelInfo *) AcquireMagickMemory(
737               sizeof(*node_info->list));
738           else
739             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
740               (size_t) (i+1),sizeof(*node_info->list));
741           if (node_info->list == (PixelInfo *) NULL)
742             {
743               (void) ThrowMagickException(exception,GetMagickModule(),
744                 ResourceLimitError,"MemoryAllocationFailed","'%s'",
745                 image->filename);
746               break;
747             }
748           node_info->list[i].red=(double) GetPixelRed(image,p);
749           node_info->list[i].green=(double) GetPixelGreen(image,p);
750           node_info->list[i].blue=(double) GetPixelBlue(image,p);
751           if (image->colorspace == CMYKColorspace)
752             node_info->list[i].black=(double) GetPixelBlack(image,p);
753           node_info->list[i].alpha=(double) GetPixelAlpha(image,p);
754           node_info->list[i].count=1;
755           node_info->number_unique++;
756           cube_info->colors++;
757           if (cube_info->colors > MaximumUniqueColors)
758             break;
759         }
760       p+=GetPixelChannels(image);
761     }
762     if (x < (ssize_t) image->columns)
763       break;
764   }
765   image_view=DestroyCacheView(image_view);
766   cube_info=DestroyCubeInfo(image,cube_info);
767   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
768 }
769 \f
770 /*
771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 %                                                                             %
773 %                                                                             %
774 %                                                                             %
775 %  I s P a l e t t e I m a g e                                                %
776 %                                                                             %
777 %                                                                             %
778 %                                                                             %
779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 %
781 %  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
782 %  unique colors or less.
783 %
784 %  The format of the IsPaletteImage method is:
785 %
786 %      MagickBooleanType IsPaletteImage(const Image *image,
787 %        ExceptionInfo *exception)
788 %
789 %  A description of each parameter follows.
790 %
791 %    o image: the image.
792 %
793 %    o exception: return any errors or warnings in this structure.
794 %
795 */
796 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
797   ExceptionInfo *exception)
798 {
799   CacheView
800     *image_view;
801
802   CubeInfo
803     *cube_info;
804
805   PixelInfo
806     pixel,
807     target;
808
809   register const Quantum
810     *p;
811
812   register ssize_t
813     x;
814
815   register NodeInfo
816     *node_info;
817
818   register ssize_t
819     i;
820
821   size_t
822     id,
823     index,
824     level;
825
826   ssize_t
827     y;
828
829   assert(image != (Image *) NULL);
830   assert(image->signature == MagickSignature);
831   if (image->debug != MagickFalse)
832     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
833   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
834     return(MagickTrue);
835   if (image->storage_class == PseudoClass)
836     return(MagickFalse);
837   /*
838     Initialize color description tree.
839   */
840   cube_info=GetCubeInfo();
841   if (cube_info == (CubeInfo *) NULL)
842     {
843       (void) ThrowMagickException(exception,GetMagickModule(),
844         ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
845       return(MagickFalse);
846     }
847   GetPixelInfo(image,&pixel);
848   GetPixelInfo(image,&target);
849   image_view=AcquireVirtualCacheView(image,exception);
850   for (y=0; y < (ssize_t) image->rows; y++)
851   {
852     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
853     if (p == (const Quantum *) NULL)
854       break;
855     for (x=0; x < (ssize_t) image->columns; x++)
856     {
857       /*
858         Start at the root and proceed level by level.
859       */
860       node_info=cube_info->root;
861       index=MaxTreeDepth-1;
862       for (level=1; level < MaxTreeDepth; level++)
863       {
864         GetPixelInfoPixel(image,p,&pixel);
865         id=ColorToNodeId(image,&pixel,index);
866         if (node_info->child[id] == (NodeInfo *) NULL)
867           {
868             node_info->child[id]=GetNodeInfo(cube_info,level);
869             if (node_info->child[id] == (NodeInfo *) NULL)
870               {
871                 (void) ThrowMagickException(exception,GetMagickModule(),
872                   ResourceLimitError,"MemoryAllocationFailed","'%s'",
873                   image->filename);
874                 break;
875               }
876           }
877         node_info=node_info->child[id];
878         index--;
879       }
880       if (level < MaxTreeDepth)
881         break;
882       for (i=0; i < (ssize_t) node_info->number_unique; i++)
883       {
884         target=node_info->list[i];
885         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
886           break;
887       }
888       if (i < (ssize_t) node_info->number_unique)
889         node_info->list[i].count++;
890       else
891         {
892           /*
893             Add this unique color to the color list.
894           */
895           if (node_info->number_unique == 0)
896             node_info->list=(PixelInfo *) AcquireMagickMemory(
897               sizeof(*node_info->list));
898           else
899             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
900               (size_t) (i+1),sizeof(*node_info->list));
901           if (node_info->list == (PixelInfo *) NULL)
902             {
903               (void) ThrowMagickException(exception,GetMagickModule(),
904                 ResourceLimitError,"MemoryAllocationFailed","'%s'",
905                 image->filename);
906               break;
907             }
908           node_info->list[i]=pixel;
909           node_info->list[i].red=(double) GetPixelRed(image,p);
910           node_info->list[i].green=(double) GetPixelGreen(image,p);
911           node_info->list[i].blue=(double) GetPixelBlue(image,p);
912           if (image->colorspace == CMYKColorspace)
913             node_info->list[i].black=(double) GetPixelBlack(image,p);
914           node_info->list[i].alpha=(double) GetPixelAlpha(image,p);
915           node_info->list[i].count=1;
916           node_info->number_unique++;
917           cube_info->colors++;
918           if (cube_info->colors > 256)
919             break;
920         }
921       p+=GetPixelChannels(image);
922     }
923     if (x < (ssize_t) image->columns)
924       break;
925   }
926   image_view=DestroyCacheView(image_view);
927   cube_info=DestroyCubeInfo(image,cube_info);
928   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
929 }
930 \f
931 /*
932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933 %                                                                             %
934 %                                                                             %
935 %                                                                             %
936 %     M i n M a x S t r e t c h I m a g e                                     %
937 %                                                                             %
938 %                                                                             %
939 %                                                                             %
940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 %
942 %  MinMaxStretchImage() uses the exact minimum and maximum values found in
943 %  each of the channels given, as the BlackPoint and WhitePoint to linearly
944 %  stretch the colors (and histogram) of the image.  The stretch points are
945 %  also moved further inward by the adjustment values given.
946 %
947 %  If the adjustment values are both zero this function is equivalent to a
948 %  perfect normalization (or autolevel) of the image.
949 %
950 %  Each channel is stretched independantally of each other (producing color
951 %  distortion) unless the special 'SyncChannels' flag is also provided in the
952 %  channels setting. If this flag is present the minimum and maximum point
953 %  will be extracted from all the given channels, and those channels will be
954 %  stretched by exactly the same amount (preventing color distortion).
955 %
956 %  In the special case that only ONE value is found in a channel of the image
957 %  that value is not stretched, that value is left as is.
958 %
959 %  The 'SyncChannels' is turned on in the 'DefaultChannels' setting by
960 %  default.
961 %
962 %  The format of the MinMaxStretchImage method is:
963 %
964 %      MagickBooleanType MinMaxStretchImage(Image *image,const double black,
965 %        const double white,const double gamma,ExceptionInfo *exception)
966 %
967 %  A description of each parameter follows:
968 %
969 %    o image: The image to auto-level
970 %
971 %    o black, white:  move the black / white point inward from the minimum and
972 %      maximum points by this color value.
973 %
974 %    o gamma: the gamma.
975 %
976 %    o exception: return any errors or warnings in this structure.
977 %
978 */
979 MagickExport MagickBooleanType MinMaxStretchImage(Image *image,
980   const double black,const double white,const double gamma,
981   ExceptionInfo *exception)
982 {
983   double
984     min,
985     max;
986
987   register ssize_t
988     i;
989
990   MagickStatusType
991     status;
992
993   status=MagickTrue;
994   if (image->channel_mask == DefaultChannels)
995     {
996       /*
997         Auto-level all channels equally.
998       */
999       (void) GetImageRange(image,&min,&max,exception);
1000       min+=black;
1001       max-=white;
1002       if (fabs(min-max) >= MagickEpsilon)
1003         status&=LevelImage(image,min,max,gamma,exception);
1004       return(status != 0 ? MagickTrue : MagickFalse);
1005     }
1006   /*
1007     Auto-level each channel separately.
1008   */
1009   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1010   {
1011     ChannelType
1012       channel_mask;
1013
1014     PixelChannel
1015       channel;
1016
1017     PixelTrait
1018       traits;
1019
1020     channel=GetPixelChannelChannel(image,i);
1021     traits=GetPixelChannelTraits(image,channel);
1022     if ((traits & UpdatePixelTrait) == 0)
1023       continue;
1024     channel_mask=SetImageChannelMask(image,(ChannelType) (1 << i));
1025     status&=GetImageRange(image,&min,&max,exception);
1026     min+=black;
1027     max-=white;
1028     if (fabs(min-max) >= MagickEpsilon)
1029       status&=LevelImage(image,min,max,gamma,exception);
1030     (void) SetImageChannelMask(image,channel_mask);
1031   }
1032   return(status != 0 ? MagickTrue : MagickFalse);
1033 }
1034 \f
1035 /*
1036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 %                                                                             %
1038 %                                                                             %
1039 %                                                                             %
1040 %  G e t N u m b e r C o l o r s                                              %
1041 %                                                                             %
1042 %                                                                             %
1043 %                                                                             %
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 %
1046 %  GetNumberColors() returns the number of unique colors in an image.
1047 %
1048 %  The format of the GetNumberColors method is:
1049 %
1050 %      size_t GetNumberColors(const Image *image,FILE *file,
1051 %        ExceptionInfo *exception)
1052 %
1053 %  A description of each parameter follows.
1054 %
1055 %    o image: the image.
1056 %
1057 %    o file:  Write a histogram of the color distribution to this file handle.
1058 %
1059 %    o exception: return any errors or warnings in this structure.
1060 %
1061 */
1062
1063 #if defined(__cplusplus) || defined(c_plusplus)
1064 extern "C" {
1065 #endif
1066
1067 static int HistogramCompare(const void *x,const void *y)
1068 {
1069   const PixelInfo
1070     *color_1,
1071     *color_2;
1072
1073   color_1=(const PixelInfo *) x;
1074   color_2=(const PixelInfo *) y;
1075   if (color_2->red != color_1->red)
1076     return((int) color_1->red-(int) color_2->red);
1077   if (color_2->green != color_1->green)
1078     return((int) color_1->green-(int) color_2->green);
1079   if (color_2->blue != color_1->blue)
1080     return((int) color_1->blue-(int) color_2->blue);
1081   return((int) color_2->count-(int) color_1->count);
1082 }
1083
1084 #if defined(__cplusplus) || defined(c_plusplus)
1085 }
1086 #endif
1087
1088 MagickExport size_t GetNumberColors(const Image *image,FILE *file,
1089   ExceptionInfo *exception)
1090 {
1091 #define HistogramImageTag  "Histogram/Image"
1092
1093   char
1094     color[MaxTextExtent],
1095     hex[MaxTextExtent],
1096     tuple[MaxTextExtent];
1097
1098   PixelInfo
1099     *histogram;
1100
1101   MagickBooleanType
1102     status;
1103
1104   PixelInfo
1105     pixel;
1106
1107   register PixelInfo
1108     *p;
1109
1110   register ssize_t
1111     i;
1112
1113   size_t
1114     number_colors;
1115
1116   number_colors=0;
1117   if (file == (FILE *) NULL)
1118     {
1119       CubeInfo
1120         *cube_info;
1121
1122       cube_info=ClassifyImageColors(image,exception);
1123       if (cube_info != (CubeInfo *) NULL)
1124         number_colors=cube_info->colors;
1125       cube_info=DestroyCubeInfo(image,cube_info);
1126       return(number_colors);
1127     }
1128   histogram=GetImageHistogram(image,&number_colors,exception);
1129   if (histogram == (PixelInfo *) NULL)
1130     return(number_colors);
1131   qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1132     HistogramCompare);
1133   GetPixelInfo(image,&pixel);
1134   p=histogram;
1135   status=MagickTrue;
1136   for (i=0; i < (ssize_t) number_colors; i++)
1137   {
1138     pixel=(*p);
1139     (void) CopyMagickString(tuple,"(",MaxTextExtent);
1140     ConcatenateColorComponent(&pixel,RedPixelChannel,X11Compliance,tuple);
1141     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1142     ConcatenateColorComponent(&pixel,GreenPixelChannel,X11Compliance,tuple);
1143     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1144     ConcatenateColorComponent(&pixel,BluePixelChannel,X11Compliance,tuple);
1145     if (pixel.colorspace == CMYKColorspace)
1146       {
1147         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1148         ConcatenateColorComponent(&pixel,BlackPixelChannel,X11Compliance,
1149           tuple);
1150       }
1151     if (pixel.alpha_trait == BlendPixelTrait)
1152       {
1153         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1154         ConcatenateColorComponent(&pixel,AlphaPixelChannel,X11Compliance,
1155           tuple);
1156       }
1157     (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1158     (void) QueryColorname(image,&pixel,SVGCompliance,color,exception);
1159     GetColorTuple(&pixel,MagickTrue,hex);
1160     (void) FormatLocaleFile(file,"%10.20g",(double) ((MagickOffsetType)
1161       p->count));
1162     (void) FormatLocaleFile(file,": %s %s %s\n",tuple,hex,color);
1163     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1164       {
1165         MagickBooleanType
1166           proceed;
1167
1168         proceed=SetImageProgress(image,HistogramImageTag,(MagickOffsetType) i,
1169           number_colors);
1170         if (proceed == MagickFalse)
1171           status=MagickFalse;
1172       }
1173     p++;
1174   }
1175   (void) fflush(file);
1176   histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
1177   if (status == MagickFalse)
1178     return(0);
1179   return(number_colors);
1180 }
1181 \f
1182 /*
1183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 %                                                                             %
1185 %                                                                             %
1186 %                                                                             %
1187 %  U n i q u e I m a g e C o l o r s                                          %
1188 %                                                                             %
1189 %                                                                             %
1190 %                                                                             %
1191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 %
1193 %  UniqueImageColors() returns the unique colors of an image.
1194 %
1195 %  The format of the UniqueImageColors method is:
1196 %
1197 %      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
1198 %
1199 %  A description of each parameter follows.
1200 %
1201 %    o image: the image.
1202 %
1203 %    o exception: return any errors or warnings in this structure.
1204 %
1205 */
1206
1207 static void UniqueColorsToImage(Image *unique_image,CacheView *unique_view,
1208   CubeInfo *cube_info,const NodeInfo *node_info,ExceptionInfo *exception)
1209 {
1210 #define UniqueColorsImageTag  "UniqueColors/Image"
1211
1212   MagickBooleanType
1213     status;
1214
1215   register ssize_t
1216     i;
1217
1218   size_t
1219     number_children;
1220
1221   /*
1222     Traverse any children.
1223   */
1224   number_children=unique_image->alpha_trait != BlendPixelTrait ? 8UL : 16UL;
1225   for (i=0; i < (ssize_t) number_children; i++)
1226     if (node_info->child[i] != (NodeInfo *) NULL)
1227       UniqueColorsToImage(unique_image,unique_view,cube_info,
1228         node_info->child[i],exception);
1229   if (node_info->level == (MaxTreeDepth-1))
1230     {
1231       register PixelInfo
1232         *p;
1233
1234       register Quantum
1235         *restrict q;
1236
1237       status=MagickTrue;
1238       p=node_info->list;
1239       for (i=0; i < (ssize_t) node_info->number_unique; i++)
1240       {
1241         q=QueueCacheViewAuthenticPixels(unique_view,cube_info->x,0,1,1,
1242           exception);
1243         if (q == (Quantum *) NULL)
1244           continue;
1245         SetPixelRed(unique_image,ClampToQuantum(p->red),q);
1246         SetPixelGreen(unique_image,ClampToQuantum(p->green),q);
1247         SetPixelBlue(unique_image,ClampToQuantum(p->blue),q);
1248         SetPixelAlpha(unique_image,ClampToQuantum(p->alpha),q);
1249         if (unique_image->colorspace == CMYKColorspace)
1250           SetPixelBlack(unique_image,ClampToQuantum(p->black),q);
1251         if (SyncCacheViewAuthenticPixels(unique_view,exception) == MagickFalse)
1252           break;
1253         cube_info->x++;
1254         p++;
1255       }
1256       if (unique_image->progress_monitor != (MagickProgressMonitor) NULL)
1257         {
1258           MagickBooleanType
1259             proceed;
1260
1261           proceed=SetImageProgress(unique_image,UniqueColorsImageTag,
1262             cube_info->progress,cube_info->colors);
1263           if (proceed == MagickFalse)
1264             status=MagickFalse;
1265         }
1266       cube_info->progress++;
1267       if (status == MagickFalse)
1268         return;
1269     }
1270 }
1271
1272 MagickExport Image *UniqueImageColors(const Image *image,
1273   ExceptionInfo *exception)
1274 {
1275   CacheView
1276     *unique_view;
1277
1278   CubeInfo
1279     *cube_info;
1280
1281   Image
1282     *unique_image;
1283
1284   cube_info=ClassifyImageColors(image,exception);
1285   if (cube_info == (CubeInfo *) NULL)
1286     return((Image *) NULL);
1287   unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
1288   if (unique_image == (Image *) NULL)
1289     return(unique_image);
1290   if (SetImageStorageClass(unique_image,DirectClass,exception) == MagickFalse)
1291     {
1292       unique_image=DestroyImage(unique_image);
1293       return((Image *) NULL);
1294     }
1295   unique_view=AcquireAuthenticCacheView(unique_image,exception);
1296   UniqueColorsToImage(unique_image,unique_view,cube_info,cube_info->root,
1297     exception);
1298   unique_view=DestroyCacheView(unique_view);
1299   if (cube_info->colors < MaxColormapSize)
1300     {
1301       QuantizeInfo
1302         *quantize_info;
1303
1304       quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
1305       quantize_info->number_colors=MaxColormapSize;
1306       quantize_info->dither_method=NoDitherMethod;
1307       quantize_info->tree_depth=8;
1308       (void) QuantizeImage(quantize_info,unique_image,exception);
1309       quantize_info=DestroyQuantizeInfo(quantize_info);
1310     }
1311   cube_info=DestroyCubeInfo(image,cube_info);
1312   return(unique_image);
1313 }