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