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