]> granicus.if.org Git - imagemagick/blob - magick/histogram.c
(no commit message)
[imagemagick] / magick / 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-2011 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 "magick/studio.h"
44 #include "magick/cache-view.h"
45 #include "magick/color-private.h"
46 #include "magick/enhance.h"
47 #include "magick/exception.h"
48 #include "magick/exception-private.h"
49 #include "magick/hashmap.h"
50 #include "magick/histogram.h"
51 #include "magick/image.h"
52 #include "magick/list.h"
53 #include "magick/memory_.h"
54 #include "magick/monitor-private.h"
55 #include "magick/pixel-private.h"
56 #include "magick/prepress.h"
57 #include "magick/quantize.h"
58 #include "magick/registry.h"
59 #include "magick/semaphore.h"
60 #include "magick/splay-tree.h"
61 #include "magick/statistic.h"
62 #include "magick/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   ColorPacket
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 MagickPixelPacket *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->matte != MagickFalse)
170     id|=((ScaleQuantumToChar(ClampToQuantum(pixel->opacity)) >> 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   ssize_t
187     y;
188
189   MagickBooleanType
190     proceed;
191
192   MagickPixelPacket
193     pixel,
194     target;
195
196   NodeInfo
197     *node_info;
198
199   register const IndexPacket
200     *indexes;
201
202   register const PixelPacket
203     *p;
204
205   register ssize_t
206     i,
207     x;
208
209   register size_t
210     id,
211     index,
212     level;
213
214   /*
215     Initialize color description tree.
216   */
217   assert(image != (const Image *) NULL);
218   assert(image->signature == MagickSignature);
219   if (image->debug != MagickFalse)
220     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
221   cube_info=GetCubeInfo();
222   if (cube_info == (CubeInfo *) NULL)
223     {
224       (void) ThrowMagickException(exception,GetMagickModule(),
225         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
226       return(cube_info);
227     }
228   GetMagickPixelPacket(image,&pixel);
229   GetMagickPixelPacket(image,&target);
230   image_view=AcquireCacheView(image);
231   for (y=0; y < (ssize_t) image->rows; y++)
232   {
233     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
234     if (p == (const PixelPacket *) NULL)
235       break;
236     indexes=GetCacheViewVirtualIndexQueue(image_view);
237     for (x=0; x < (ssize_t) image->columns; x++)
238     {
239       /*
240         Start at the root and proceed level by level.
241       */
242       node_info=cube_info->root;
243       index=MaxTreeDepth-1;
244       for (level=1; level < MaxTreeDepth; level++)
245       {
246         SetMagickPixelPacket(image,p,indexes+x,&pixel);
247         id=ColorToNodeId(image,&pixel,index);
248         if (node_info->child[id] == (NodeInfo *) NULL)
249           {
250             node_info->child[id]=GetNodeInfo(cube_info,level);
251             if (node_info->child[id] == (NodeInfo *) NULL)
252               {
253                 (void) ThrowMagickException(exception,GetMagickModule(),
254                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
255                   image->filename);
256                 return(0);
257               }
258           }
259         node_info=node_info->child[id];
260         index--;
261       }
262       for (i=0; i < (ssize_t) node_info->number_unique; i++)
263       {
264         SetMagickPixelPacket(image,&node_info->list[i].pixel,
265           &node_info->list[i].index,&target);
266         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
267           break;
268       }
269       if (i < (ssize_t) node_info->number_unique)
270         node_info->list[i].count++;
271       else
272         {
273           if (node_info->number_unique == 0)
274             node_info->list=(ColorPacket *) AcquireMagickMemory(
275               sizeof(*node_info->list));
276           else
277             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
278               (size_t) (i+1),sizeof(*node_info->list));
279           if (node_info->list == (ColorPacket *) NULL)
280             {
281               (void) ThrowMagickException(exception,GetMagickModule(),
282                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
283                 image->filename);
284               return(0);
285             }
286           node_info->list[i].pixel=(*p);
287           if ((image->colorspace == CMYKColorspace) ||
288               (image->storage_class == PseudoClass))
289             node_info->list[i].index=indexes[x];
290           node_info->list[i].count=1;
291           node_info->number_unique++;
292           cube_info->colors++;
293         }
294       p++;
295     }
296     proceed=SetImageProgress(image,EvaluateImageTag,(MagickOffsetType) y,
297       image->rows);
298     if (proceed == MagickFalse)
299       break;
300   }
301   image_view=DestroyCacheView(image_view);
302   return(cube_info);
303 }
304 \f
305 /*
306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307 %                                                                             %
308 %                                                                             %
309 %                                                                             %
310 +   D e f i n e I m a g e H i s t o g r a m                                   %
311 %                                                                             %
312 %                                                                             %
313 %                                                                             %
314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 %
316 %  DefineImageHistogram() traverses the color cube tree and notes each colormap
317 %  entry.  A colormap entry is any node in the color cube tree where the
318 %  of unique colors is not zero.
319 %
320 %  The format of the DefineImageHistogram method is:
321 %
322 %      DefineImageHistogram(const Image *image,NodeInfo *node_info,
323 %        ColorPacket **unique_colors)
324 %
325 %  A description of each parameter follows.
326 %
327 %    o image: the image.
328 %
329 %    o node_info: the address of a structure of type NodeInfo which points to a
330 %      node in the color cube tree that is to be pruned.
331 %
332 %    o histogram: the image histogram.
333 %
334 */
335 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
336   ColorPacket **histogram)
337 {
338   register ssize_t
339     i;
340
341   size_t
342     number_children;
343
344   /*
345     Traverse any children.
346   */
347   number_children=image->matte == MagickFalse ? 8UL : 16UL;
348   for (i=0; i < (ssize_t) number_children; i++)
349     if (node_info->child[i] != (NodeInfo *) NULL)
350       DefineImageHistogram(image,node_info->child[i],histogram);
351   if (node_info->level == (MaxTreeDepth-1))
352     {
353       register ColorPacket
354         *p;
355
356       p=node_info->list;
357       for (i=0; i < (ssize_t) node_info->number_unique; i++)
358       {
359         (*histogram)->pixel=p->pixel;
360         (*histogram)->index=p->index;
361         (*histogram)->count=p->count;
362         (*histogram)++;
363         p++;
364       }
365     }
366 }
367 \f
368 /*
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %                                                                             %
371 %                                                                             %
372 %                                                                             %
373 +   D e s t r o y C u b e I n f o                                             %
374 %                                                                             %
375 %                                                                             %
376 %                                                                             %
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 %
379 %  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
380 %
381 %  The format of the DestroyCubeInfo method is:
382 %
383 %      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
384 %
385 %  A description of each parameter follows:
386 %
387 %    o image: the image.
388 %
389 %    o cube_info: the address of a structure of type CubeInfo.
390 %
391 */
392 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
393 {
394   register Nodes
395     *nodes;
396
397   /*
398     Release color cube tree storage.
399   */
400   DestroyColorCube(image,cube_info->root);
401   do
402   {
403     nodes=cube_info->node_queue->next;
404     cube_info->node_queue=(Nodes *)
405       RelinquishMagickMemory(cube_info->node_queue);
406     cube_info->node_queue=nodes;
407   } while (cube_info->node_queue != (Nodes *) NULL);
408   return((CubeInfo *) RelinquishMagickMemory(cube_info));
409 }
410 \f
411 /*
412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 %                                                                             %
414 %                                                                             %
415 %                                                                             %
416 +  D e s t r o y C o l o r C u b e                                            %
417 %                                                                             %
418 %                                                                             %
419 %                                                                             %
420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 %
422 %  DestroyColorCube() traverses the color cube tree and frees the list of
423 %  unique colors.
424 %
425 %  The format of the DestroyColorCube method is:
426 %
427 %      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
428 %
429 %  A description of each parameter follows.
430 %
431 %    o image: the image.
432 %
433 %    o node_info: the address of a structure of type NodeInfo which points to a
434 %      node in the color cube tree that is to be pruned.
435 %
436 */
437 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
438 {
439   register ssize_t
440     i;
441
442   size_t
443     number_children;
444
445   /*
446     Traverse any children.
447   */
448   number_children=image->matte == MagickFalse ? 8UL : 16UL;
449   for (i=0; i < (ssize_t) number_children; i++)
450     if (node_info->child[i] != (NodeInfo *) NULL)
451       DestroyColorCube(image,node_info->child[i]);
452   if (node_info->list != (ColorPacket *) NULL)
453     node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list);
454 }
455 \f
456 /*
457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458 %                                                                             %
459 %                                                                             %
460 %                                                                             %
461 +   G e t C u b e I n f o                                                     %
462 %                                                                             %
463 %                                                                             %
464 %                                                                             %
465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 %
467 %  GetCubeInfo() initializes the CubeInfo data structure.
468 %
469 %  The format of the GetCubeInfo method is:
470 %
471 %      cube_info=GetCubeInfo()
472 %
473 %  A description of each parameter follows.
474 %
475 %    o cube_info: A pointer to the Cube structure.
476 %
477 */
478 static CubeInfo *GetCubeInfo(void)
479 {
480   CubeInfo
481     *cube_info;
482
483   /*
484     Initialize tree to describe color cube.
485   */
486   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
487   if (cube_info == (CubeInfo *) NULL)
488     return((CubeInfo *) NULL);
489   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
490   /*
491     Initialize root node.
492   */
493   cube_info->root=GetNodeInfo(cube_info,0);
494   if (cube_info->root == (NodeInfo *) NULL)
495     return((CubeInfo *) NULL);
496   return(cube_info);
497 }
498 \f
499 /*
500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501 %                                                                             %
502 %                                                                             %
503 %                                                                             %
504 %  G e t I m a g e H i s t o g r a m                                          %
505 %                                                                             %
506 %                                                                             %
507 %                                                                             %
508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509 %
510 %  GetImageHistogram() returns the unique colors in an image.
511 %
512 %  The format of the GetImageHistogram method is:
513 %
514 %      size_t GetImageHistogram(const Image *image,
515 %        size_t *number_colors,ExceptionInfo *exception)
516 %
517 %  A description of each parameter follows.
518 %
519 %    o image: the image.
520 %
521 %    o file:  Write a histogram of the color distribution to this file handle.
522 %
523 %    o exception: return any errors or warnings in this structure.
524 %
525 */
526 MagickExport ColorPacket *GetImageHistogram(const Image *image,
527   size_t *number_colors,ExceptionInfo *exception)
528 {
529   ColorPacket
530     *histogram;
531
532   CubeInfo
533     *cube_info;
534
535   *number_colors=0;
536   histogram=(ColorPacket *) NULL;
537   cube_info=ClassifyImageColors(image,exception);
538   if (cube_info != (CubeInfo *) NULL)
539     {
540       histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
541         sizeof(*histogram));
542       if (histogram == (ColorPacket *) NULL)
543         (void) ThrowMagickException(exception,GetMagickModule(),
544           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
545       else
546         {
547           ColorPacket
548             *root;
549
550           *number_colors=cube_info->colors;
551           root=histogram;
552           DefineImageHistogram(image,cube_info->root,&root);
553         }
554     }
555   cube_info=DestroyCubeInfo(image,cube_info);
556   return(histogram);
557 }
558 \f
559 /*
560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561 %                                                                             %
562 %                                                                             %
563 %                                                                             %
564 +  G e t N o d e I n f o                                                      %
565 %                                                                             %
566 %                                                                             %
567 %                                                                             %
568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
569 %
570 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
571 %  presets all fields to zero.
572 %
573 %  The format of the GetNodeInfo method is:
574 %
575 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
576 %
577 %  A description of each parameter follows.
578 %
579 %    o cube_info: A pointer to the CubeInfo structure.
580 %
581 %    o level: Specifies the level in the storage_class the node resides.
582 %
583 */
584 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
585 {
586   NodeInfo
587     *node_info;
588
589   if (cube_info->free_nodes == 0)
590     {
591       Nodes
592         *nodes;
593
594       /*
595         Allocate a new nodes of nodes.
596       */
597       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
598       if (nodes == (Nodes *) NULL)
599         return((NodeInfo *) NULL);
600       nodes->next=cube_info->node_queue;
601       cube_info->node_queue=nodes;
602       cube_info->node_info=nodes->nodes;
603       cube_info->free_nodes=NodesInAList;
604     }
605   cube_info->free_nodes--;
606   node_info=cube_info->node_info++;
607   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
608   node_info->level=level;
609   return(node_info);
610 }
611 \f
612 /*
613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 %                                                                             %
615 %                                                                             %
616 %                                                                             %
617 %  I s H i s t o g r a m I m a g e                                            %
618 %                                                                             %
619 %                                                                             %
620 %                                                                             %
621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 %
623 %  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
624 %  less.
625 %
626 %  The format of the IsHistogramImage method is:
627 %
628 %      MagickBooleanType IsHistogramImage(const Image *image,
629 %        ExceptionInfo *exception)
630 %
631 %  A description of each parameter follows.
632 %
633 %    o image: the image.
634 %
635 %    o exception: return any errors or warnings in this structure.
636 %
637 */
638 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
639   ExceptionInfo *exception)
640 {
641 #define MaximumUniqueColors  1024
642
643   CacheView
644     *image_view;
645
646   CubeInfo
647     *cube_info;
648
649   ssize_t
650     y;
651
652   MagickPixelPacket
653     pixel,
654     target;
655
656   register const IndexPacket
657     *indexes;
658
659   register const PixelPacket
660     *p;
661
662   register ssize_t
663     x;
664
665   register NodeInfo
666     *node_info;
667
668   register ssize_t
669     i;
670
671   size_t
672     id,
673     index,
674     level;
675
676   assert(image != (Image *) NULL);
677   assert(image->signature == MagickSignature);
678   if (image->debug != MagickFalse)
679     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
680   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
681     return(MagickTrue);
682   if (image->storage_class == PseudoClass)
683     return(MagickFalse);
684   /*
685     Initialize color description tree.
686   */
687   cube_info=GetCubeInfo();
688   if (cube_info == (CubeInfo *) NULL)
689     {
690       (void) ThrowMagickException(exception,GetMagickModule(),
691         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
692       return(MagickFalse);
693     }
694   GetMagickPixelPacket(image,&pixel);
695   GetMagickPixelPacket(image,&target);
696   image_view=AcquireCacheView(image);
697   for (y=0; y < (ssize_t) image->rows; y++)
698   {
699     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
700     if (p == (const PixelPacket *) NULL)
701       break;
702     indexes=GetCacheViewVirtualIndexQueue(image_view);
703     for (x=0; x < (ssize_t) image->columns; x++)
704     {
705       /*
706         Start at the root and proceed level by level.
707       */
708       node_info=cube_info->root;
709       index=MaxTreeDepth-1;
710       for (level=1; level < MaxTreeDepth; level++)
711       {
712         SetMagickPixelPacket(image,p,indexes+x,&pixel);
713         id=ColorToNodeId(image,&pixel,index);
714         if (node_info->child[id] == (NodeInfo *) NULL)
715           {
716             node_info->child[id]=GetNodeInfo(cube_info,level);
717             if (node_info->child[id] == (NodeInfo *) NULL)
718               {
719                 (void) ThrowMagickException(exception,GetMagickModule(),
720                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
721                   image->filename);
722                 break;
723               }
724           }
725         node_info=node_info->child[id];
726         index--;
727       }
728       if (level < MaxTreeDepth)
729         break;
730       for (i=0; i < (ssize_t) node_info->number_unique; i++)
731       {
732         SetMagickPixelPacket(image,&node_info->list[i].pixel,
733           &node_info->list[i].index,&target);
734         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
735           break;
736       }
737       if (i < (ssize_t) node_info->number_unique)
738         node_info->list[i].count++;
739       else
740         {
741           /*
742             Add this unique color to the color list.
743           */
744           if (node_info->number_unique == 0)
745             node_info->list=(ColorPacket *) AcquireMagickMemory(
746               sizeof(*node_info->list));
747           else
748             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
749               (size_t) (i+1),sizeof(*node_info->list));
750           if (node_info->list == (ColorPacket *) NULL)
751             {
752               (void) ThrowMagickException(exception,GetMagickModule(),
753                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
754                 image->filename);
755               break;
756             }
757           node_info->list[i].pixel=(*p);
758           if ((image->colorspace == CMYKColorspace) ||
759               (image->storage_class == PseudoClass))
760             node_info->list[i].index=indexes[x];
761           node_info->list[i].count=1;
762           node_info->number_unique++;
763           cube_info->colors++;
764           if (cube_info->colors > MaximumUniqueColors)
765             break;
766         }
767       p++;
768     }
769     if (x < (ssize_t) image->columns)
770       break;
771   }
772   image_view=DestroyCacheView(image_view);
773   cube_info=DestroyCubeInfo(image,cube_info);
774   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
775 }
776 \f
777 /*
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779 %                                                                             %
780 %                                                                             %
781 %                                                                             %
782 %  I s P a l e t t e I m a g e                                                %
783 %                                                                             %
784 %                                                                             %
785 %                                                                             %
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 %
788 %  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
789 %  unique colors or less.
790 %
791 %  The format of the IsPaletteImage method is:
792 %
793 %      MagickBooleanType IsPaletteImage(const Image *image,
794 %        ExceptionInfo *exception)
795 %
796 %  A description of each parameter follows.
797 %
798 %    o image: the image.
799 %
800 %    o exception: return any errors or warnings in this structure.
801 %
802 */
803 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
804   ExceptionInfo *exception)
805 {
806   CacheView
807     *image_view;
808
809   CubeInfo
810     *cube_info;
811
812   ssize_t
813     y;
814
815   MagickPixelPacket
816     pixel,
817     target;
818
819   register const IndexPacket
820     *indexes;
821
822   register const PixelPacket
823     *p;
824
825   register ssize_t
826     x;
827
828   register NodeInfo
829     *node_info;
830
831   register ssize_t
832     i;
833
834   size_t
835     id,
836     index,
837     level;
838
839   assert(image != (Image *) NULL);
840   assert(image->signature == MagickSignature);
841   if (image->debug != MagickFalse)
842     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
843   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
844     return(MagickTrue);
845   if (image->storage_class == PseudoClass)
846     return(MagickFalse);
847   /*
848     Initialize color description tree.
849   */
850   cube_info=GetCubeInfo();
851   if (cube_info == (CubeInfo *) NULL)
852     {
853       (void) ThrowMagickException(exception,GetMagickModule(),
854         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
855       return(MagickFalse);
856     }
857   GetMagickPixelPacket(image,&pixel);
858   GetMagickPixelPacket(image,&target);
859   image_view=AcquireCacheView(image);
860   for (y=0; y < (ssize_t) image->rows; y++)
861   {
862     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
863     if (p == (const PixelPacket *) NULL)
864       break;
865     indexes=GetCacheViewVirtualIndexQueue(image_view);
866     for (x=0; x < (ssize_t) image->columns; x++)
867     {
868       /*
869         Start at the root and proceed level by level.
870       */
871       node_info=cube_info->root;
872       index=MaxTreeDepth-1;
873       for (level=1; level < MaxTreeDepth; level++)
874       {
875         SetMagickPixelPacket(image,p,indexes+x,&pixel);
876         id=ColorToNodeId(image,&pixel,index);
877         if (node_info->child[id] == (NodeInfo *) NULL)
878           {
879             node_info->child[id]=GetNodeInfo(cube_info,level);
880             if (node_info->child[id] == (NodeInfo *) NULL)
881               {
882                 (void) ThrowMagickException(exception,GetMagickModule(),
883                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
884                   image->filename);
885                 break;
886               }
887           }
888         node_info=node_info->child[id];
889         index--;
890       }
891       if (level < MaxTreeDepth)
892         break;
893       for (i=0; i < (ssize_t) node_info->number_unique; i++)
894       {
895         SetMagickPixelPacket(image,&node_info->list[i].pixel,
896           &node_info->list[i].index,&target);
897         if (IsMagickColorEqual(&pixel,&target) != MagickFalse)
898           break;
899       }
900       if (i < (ssize_t) node_info->number_unique)
901         node_info->list[i].count++;
902       else
903         {
904           /*
905             Add this unique color to the color list.
906           */
907           if (node_info->number_unique == 0)
908             node_info->list=(ColorPacket *) AcquireMagickMemory(
909               sizeof(*node_info->list));
910           else
911             node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list,
912               (size_t) (i+1),sizeof(*node_info->list));
913           if (node_info->list == (ColorPacket *) NULL)
914             {
915               (void) ThrowMagickException(exception,GetMagickModule(),
916                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
917                 image->filename);
918               break;
919             }
920           node_info->list[i].pixel=(*p);
921           if ((image->colorspace == CMYKColorspace) ||
922               (image->storage_class == PseudoClass))
923             node_info->list[i].index=indexes[x];
924           node_info->list[i].count=1;
925           node_info->number_unique++;
926           cube_info->colors++;
927           if (cube_info->colors > 256)
928             break;
929         }
930       p++;
931     }
932     if (x < (ssize_t) image->columns)
933       break;
934   }
935   image_view=DestroyCacheView(image_view);
936   cube_info=DestroyCubeInfo(image,cube_info);
937   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
938 }
939 \f
940 /*
941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
942 %                                                                             %
943 %                                                                             %
944 %                                                                             %
945 %     M i n M a x S t r e t c h I m a g e                                     %
946 %                                                                             %
947 %                                                                             %
948 %                                                                             %
949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
950 %
951 %  MinMaxStretchImage() uses the exact minimum and maximum values found in
952 %  each of the channels given, as the BlackPoint and WhitePoint to linearly
953 %  stretch the colors (and histogram) of the image.  The stretch points are
954 %  also moved further inward by the adjustment values given.
955 %
956 %  If the adjustment values are both zero this function is equivelent to a
957 %  perfect normalization (or autolevel) of the image.
958 %
959 %  Each channel is stretched independantally of each other (producing color
960 %  distortion) unless the special 'SyncChannels' flag is also provided in the
961 %  channels setting. If this flag is present the minimum and maximum point
962 %  will be extracted from all the given channels, and those channels will be
963 %  stretched by exactly the same amount (preventing color distortion).
964 %
965 %  In the special case that only ONE value is found in a channel of the image
966 %  that value is not stretched, that value is left as is.
967 %
968 %  The 'SyncChannels' is turned on in the 'DefaultChannels' setting by
969 %  default.
970 %
971 %  The format of the MinMaxStretchImage method is:
972 %
973 %      MagickBooleanType MinMaxStretchImage(Image *image,
974 %        const ChannelType channel, const double black_adjust,
975 %        const double white_adjust)
976 %
977 %  A description of each parameter follows:
978 %
979 %    o image: The image to auto-level
980 %
981 %    o channel: The channels to auto-level.  If the special 'SyncChannels'
982 %      flag is set, all the given channels are stretched by the same amount.
983 %
984 %    o black_adjust, white_adjust:  Move the Black/White Point inward
985 %      from the minimum and maximum points by this color value.
986 %
987 */
988
989 MagickExport MagickBooleanType MinMaxStretchImage(Image *image,
990   const ChannelType channel,const double black_value,const double white_value)
991 {
992   double
993     min,
994     max;
995
996   MagickStatusType
997     status;
998
999   status=MagickTrue;
1000   if ((channel & SyncChannels) != 0)
1001     {
1002       /*
1003         Auto-level all channels equally.
1004       */
1005       (void) GetImageChannelRange(image,channel,&min,&max,&image->exception);
1006       min+=black_value;
1007       max-=white_value;
1008       if (fabs(min-max) >= MagickEpsilon)
1009         status&=LevelImageChannel(image,channel,min,max,1.0);
1010       return(status != 0 ? MagickTrue : MagickFalse);
1011     }
1012   /*
1013     Auto-level each channel separately.
1014   */
1015   if ((channel & RedChannel) != 0)
1016     {
1017       (void) GetImageChannelRange(image,RedChannel,&min,&max,&image->exception);
1018       min+=black_value;
1019       max-=white_value;
1020       if (fabs(min-max) >= MagickEpsilon)
1021         status&=LevelImageChannel(image,RedChannel,min,max,1.0);
1022     }
1023   if ((channel & GreenChannel) != 0)
1024     {
1025       (void) GetImageChannelRange(image,GreenChannel,&min,&max,
1026         &image->exception);
1027       min+=black_value;
1028       max-=white_value;
1029       if (fabs(min-max) >= MagickEpsilon)
1030         status&=LevelImageChannel(image,GreenChannel,min,max,1.0);
1031     }
1032   if ((channel & BlueChannel) != 0)
1033     {
1034       (void) GetImageChannelRange(image,BlueChannel,&min,&max,
1035         &image->exception);
1036       min+=black_value;
1037       max-=white_value;
1038       if (fabs(min-max) >= MagickEpsilon)
1039         status&=LevelImageChannel(image,BlueChannel,min,max,1.0);
1040     }
1041   if (((channel & OpacityChannel) != 0) &&
1042        (image->matte == MagickTrue))
1043     {
1044       (void) GetImageChannelRange(image,OpacityChannel,&min,&max,
1045         &image->exception);
1046       min+=black_value;
1047       max-=white_value;
1048       if (fabs(min-max) >= MagickEpsilon)
1049         status&=LevelImageChannel(image,OpacityChannel,min,max,1.0);
1050     }
1051   if (((channel & IndexChannel) != 0) &&
1052        (image->colorspace == CMYKColorspace))
1053     {
1054       (void) GetImageChannelRange(image,IndexChannel,&min,&max,
1055         &image->exception);
1056       min+=black_value;
1057       max-=white_value;
1058       if (fabs(min-max) >= MagickEpsilon)
1059         status&=LevelImageChannel(image,IndexChannel,min,max,1.0);
1060     }
1061   return(status != 0 ? MagickTrue : MagickFalse);
1062 }
1063 \f
1064 /*
1065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066 %                                                                             %
1067 %                                                                             %
1068 %                                                                             %
1069 %  G e t N u m b e r C o l o r s                                              %
1070 %                                                                             %
1071 %                                                                             %
1072 %                                                                             %
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 %
1075 %  GetNumberColors() returns the number of unique colors in an image.
1076 %
1077 %  The format of the GetNumberColors method is:
1078 %
1079 %      size_t GetNumberColors(const Image *image,FILE *file,
1080 %        ExceptionInfo *exception)
1081 %
1082 %  A description of each parameter follows.
1083 %
1084 %    o image: the image.
1085 %
1086 %    o file:  Write a histogram of the color distribution to this file handle.
1087 %
1088 %    o exception: return any errors or warnings in this structure.
1089 %
1090 */
1091
1092 #if defined(__cplusplus) || defined(c_plusplus)
1093 extern "C" {
1094 #endif
1095
1096 static int HistogramCompare(const void *x,const void *y)
1097 {
1098   const ColorPacket
1099     *color_1,
1100     *color_2;
1101
1102   color_1=(const ColorPacket *) x;
1103   color_2=(const ColorPacket *) y;
1104   if (color_2->pixel.red != color_1->pixel.red)
1105     return((int) color_1->pixel.red-(int) color_2->pixel.red);
1106   if (color_2->pixel.green != color_1->pixel.green)
1107     return((int) color_1->pixel.green-(int) color_2->pixel.green);
1108   if (color_2->pixel.blue != color_1->pixel.blue)
1109     return((int) color_1->pixel.blue-(int) color_2->pixel.blue);
1110   return((int) color_2->count-(int) color_1->count);
1111 }
1112
1113 #if defined(__cplusplus) || defined(c_plusplus)
1114 }
1115 #endif
1116
1117 MagickExport size_t GetNumberColors(const Image *image,FILE *file,
1118   ExceptionInfo *exception)
1119 {
1120 #define HistogramImageTag  "Histogram/Image"
1121
1122   char
1123     color[MaxTextExtent],
1124     hex[MaxTextExtent],
1125     tuple[MaxTextExtent];
1126
1127   ColorPacket
1128     *histogram;
1129
1130   MagickBooleanType
1131     status;
1132
1133   MagickPixelPacket
1134     pixel;
1135
1136   register ColorPacket
1137     *p;
1138
1139   register ssize_t
1140     i;
1141
1142   size_t
1143     number_colors;
1144
1145   number_colors=0;
1146   if (file == (FILE *) NULL)
1147     {
1148       CubeInfo
1149         *cube_info;
1150
1151       cube_info=ClassifyImageColors(image,exception);
1152       if (cube_info != (CubeInfo *) NULL)
1153         number_colors=cube_info->colors;
1154       cube_info=DestroyCubeInfo(image,cube_info);
1155       return(number_colors);
1156     }
1157   histogram=GetImageHistogram(image,&number_colors,exception);
1158   if (histogram == (ColorPacket *) NULL)
1159     return(number_colors);
1160   qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
1161     HistogramCompare);
1162   GetMagickPixelPacket(image,&pixel);
1163   p=histogram;
1164   for (i=0; i < (ssize_t) number_colors; i++)
1165   {
1166     SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel);
1167     (void) CopyMagickString(tuple,"(",MaxTextExtent);
1168     ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1169     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1170     ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1171     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1172     ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1173     if (pixel.colorspace == CMYKColorspace)
1174       {
1175         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1176         ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
1177       }
1178     if (pixel.matte != MagickFalse)
1179       {
1180         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1181         ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
1182       }
1183     (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1184     (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
1185     GetColorTuple(&pixel,MagickTrue,hex);
1186     (void) fprintf(file,"%10" MagickSizeFormat,p->count);
1187     (void) fprintf(file,": %s %s %s\n",tuple,hex,color);
1188     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1189       {
1190         MagickBooleanType
1191           proceed;
1192
1193         proceed=SetImageProgress(image,HistogramImageTag,(MagickOffsetType) i,
1194           number_colors);
1195         if (proceed == MagickFalse)
1196           status=MagickFalse;
1197       }
1198     p++;
1199   }
1200   (void) fflush(file);
1201   histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
1202   return(number_colors);
1203 }
1204 \f
1205 /*
1206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207 %                                                                             %
1208 %                                                                             %
1209 %                                                                             %
1210 %  U n i q u e I m a g e C o l o r s                                          %
1211 %                                                                             %
1212 %                                                                             %
1213 %                                                                             %
1214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 %
1216 %  UniqueImageColors() returns the unique colors of an image.
1217 %
1218 %  The format of the UniqueImageColors method is:
1219 %
1220 %      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
1221 %
1222 %  A description of each parameter follows.
1223 %
1224 %    o image: the image.
1225 %
1226 %    o exception: return any errors or warnings in this structure.
1227 %
1228 */
1229
1230 static void UniqueColorsToImage(Image *unique_image,CacheView *unique_view,
1231   CubeInfo *cube_info,const NodeInfo *node_info,ExceptionInfo *exception)
1232 {
1233 #define UniqueColorsImageTag  "UniqueColors/Image"
1234
1235   MagickBooleanType
1236     status;
1237
1238   register ssize_t
1239     i;
1240
1241   size_t
1242     number_children;
1243
1244   /*
1245     Traverse any children.
1246   */
1247   number_children=unique_image->matte == MagickFalse ? 8UL : 16UL;
1248   for (i=0; i < (ssize_t) number_children; i++)
1249     if (node_info->child[i] != (NodeInfo *) NULL)
1250       UniqueColorsToImage(unique_image,unique_view,cube_info,
1251         node_info->child[i],exception);
1252   if (node_info->level == (MaxTreeDepth-1))
1253     {
1254       register ColorPacket
1255         *p;
1256
1257       register IndexPacket
1258         *restrict indexes;
1259
1260       register PixelPacket
1261         *restrict q;
1262
1263       p=node_info->list;
1264       for (i=0; i < (ssize_t) node_info->number_unique; i++)
1265       {
1266         q=QueueCacheViewAuthenticPixels(unique_view,cube_info->x,0,1,1,
1267           exception);
1268         if (q == (PixelPacket *) NULL)
1269           continue;
1270         indexes=GetCacheViewAuthenticIndexQueue(unique_view);
1271         *q=p->pixel;
1272         if (unique_image->colorspace == CMYKColorspace)
1273           *indexes=p->index;
1274         if (SyncCacheViewAuthenticPixels(unique_view,exception) == MagickFalse)
1275           break;
1276         cube_info->x++;
1277         p++;
1278       }
1279       if (unique_image->progress_monitor != (MagickProgressMonitor) NULL)
1280         {
1281           MagickBooleanType
1282             proceed;
1283
1284           proceed=SetImageProgress(unique_image,UniqueColorsImageTag,
1285             cube_info->progress,cube_info->colors);
1286           if (proceed == MagickFalse)
1287             status=MagickFalse;
1288         }
1289       cube_info->progress++;
1290     }
1291 }
1292
1293 MagickExport Image *UniqueImageColors(const Image *image,
1294   ExceptionInfo *exception)
1295 {
1296   CacheView
1297     *unique_view;
1298
1299   CubeInfo
1300     *cube_info;
1301
1302   Image
1303     *unique_image;
1304
1305   cube_info=ClassifyImageColors(image,exception);
1306   if (cube_info == (CubeInfo *) NULL)
1307     return((Image *) NULL);
1308   unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
1309   if (unique_image == (Image *) NULL)
1310     return(unique_image);
1311   if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
1312     {
1313       InheritException(exception,&unique_image->exception);
1314       unique_image=DestroyImage(unique_image);
1315       return((Image *) NULL);
1316     }
1317   unique_view=AcquireCacheView(unique_image);
1318   UniqueColorsToImage(unique_image,unique_view,cube_info,cube_info->root,
1319     exception);
1320   unique_view=DestroyCacheView(unique_view);
1321   if (cube_info->colors < MaxColormapSize)
1322     {
1323       QuantizeInfo
1324         *quantize_info;
1325
1326       quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
1327       quantize_info->number_colors=MaxColormapSize;
1328       quantize_info->dither=MagickFalse;
1329       quantize_info->tree_depth=8;
1330       (void) QuantizeImage(quantize_info,unique_image);
1331       quantize_info=DestroyQuantizeInfo(quantize_info);
1332     }
1333   cube_info=DestroyCubeInfo(image,cube_info);
1334   return(unique_image);
1335 }