MagickCore  6.7.5
histogram.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %      H   H   IIIII   SSSSS  TTTTT   OOO    GGGG  RRRR    AAA   M   M        %
00007 %      H   H     I     SS       T    O   O  G      R   R  A   A  MM MM        %
00008 %      HHHHH     I      SSS     T    O   O  G  GG  RRRR   AAAAA  M M M        %
00009 %      H   H     I        SS    T    O   O  G   G  R R    A   A  M   M        %
00010 %      H   H   IIIII   SSSSS    T     OOO    GGG   R  R   A   A  M   M        %
00011 %                                                                             %
00012 %                                                                             %
00013 %                        MagickCore Histogram Methods                         %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                              Anthony Thyssen                                %
00017 %                               Fred Weinhaus                                 %
00018 %                                August 2009                                  %
00019 %                                                                             %
00020 %                                                                             %
00021 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00022 %  dedicated to making software imaging solutions freely available.           %
00023 %                                                                             %
00024 %  You may not use this file except in compliance with the License.  You may  %
00025 %  obtain a copy of the License at                                            %
00026 %                                                                             %
00027 %    http://www.imagemagick.org/script/license.php                            %
00028 %                                                                             %
00029 %  Unless required by applicable law or agreed to in writing, software        %
00030 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00031 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00032 %  See the License for the specific language governing permissions and        %
00033 %  limitations under the License.                                             %
00034 %                                                                             %
00035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/cache-view.h"
00045 #include "MagickCore/color-private.h"
00046 #include "MagickCore/enhance.h"
00047 #include "MagickCore/exception.h"
00048 #include "MagickCore/exception-private.h"
00049 #include "MagickCore/hashmap.h"
00050 #include "MagickCore/histogram.h"
00051 #include "MagickCore/image.h"
00052 #include "MagickCore/list.h"
00053 #include "MagickCore/memory_.h"
00054 #include "MagickCore/monitor-private.h"
00055 #include "MagickCore/pixel-accessor.h"
00056 #include "MagickCore/prepress.h"
00057 #include "MagickCore/quantize.h"
00058 #include "MagickCore/registry.h"
00059 #include "MagickCore/semaphore.h"
00060 #include "MagickCore/splay-tree.h"
00061 #include "MagickCore/statistic.h"
00062 #include "MagickCore/string_.h"
00063 
00064 /*
00065   Define declarations.
00066 */
00067 #define MaxTreeDepth  8
00068 #define NodesInAList  1536
00069 
00070 /*
00071   Typedef declarations.
00072 */
00073 typedef struct _NodeInfo
00074 {
00075   struct _NodeInfo
00076     *child[16];
00077 
00078   PixelInfo
00079     *list;
00080 
00081   MagickSizeType
00082     number_unique;
00083 
00084   size_t
00085     level;
00086 } NodeInfo;
00087 
00088 typedef struct _Nodes
00089 {
00090   NodeInfo
00091     nodes[NodesInAList];
00092 
00093   struct _Nodes
00094     *next;
00095 } Nodes;
00096 
00097 typedef struct _CubeInfo
00098 {
00099   NodeInfo
00100     *root;
00101 
00102   ssize_t
00103     x;
00104 
00105   MagickOffsetType
00106     progress;
00107 
00108   size_t
00109     colors,
00110     free_nodes;
00111 
00112   NodeInfo
00113     *node_info;
00114 
00115   Nodes
00116     *node_queue;
00117 } CubeInfo;
00118 
00119 /*
00120   Forward declarations.
00121 */
00122 static CubeInfo
00123   *GetCubeInfo(void);
00124 
00125 static NodeInfo
00126   *GetNodeInfo(CubeInfo *,const size_t);
00127 
00128 static void
00129   DestroyColorCube(const Image *,NodeInfo *);
00130 
00131 /*
00132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00133 %                                                                             %
00134 %                                                                             %
00135 %                                                                             %
00136 +   C l a s s i f y I m a g e C o l o r s                                     %
00137 %                                                                             %
00138 %                                                                             %
00139 %                                                                             %
00140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00141 %
00142 %  ClassifyImageColors() builds a populated CubeInfo tree for the specified
00143 %  image.  The returned tree should be deallocated using DestroyCubeInfo()
00144 %  once it is no longer needed.
00145 %
00146 %  The format of the ClassifyImageColors() method is:
00147 %
00148 %      CubeInfo *ClassifyImageColors(const Image *image,
00149 %        ExceptionInfo *exception)
00150 %
00151 %  A description of each parameter follows.
00152 %
00153 %    o image: the image.
00154 %
00155 %    o exception: return any errors or warnings in this structure.
00156 %
00157 */
00158 
00159 static inline size_t ColorToNodeId(const Image *image,
00160   const PixelInfo *pixel,size_t index)
00161 {
00162   size_t
00163     id;
00164 
00165   id=(size_t) (
00166     ((ScaleQuantumToChar(ClampToQuantum(pixel->red)) >> index) & 0x01) |
00167     ((ScaleQuantumToChar(ClampToQuantum(pixel->green)) >> index) & 0x01) << 1 |
00168     ((ScaleQuantumToChar(ClampToQuantum(pixel->blue)) >> index) & 0x01) << 2);
00169   if (image->matte != MagickFalse)
00170     id|=((ScaleQuantumToChar(ClampToQuantum(pixel->alpha)) >> index) &
00171       0x01) << 3;
00172   return(id);
00173 }
00174 
00175 static CubeInfo *ClassifyImageColors(const Image *image,
00176   ExceptionInfo *exception)
00177 {
00178 #define EvaluateImageTag  "  Compute image colors...  "
00179 
00180   CacheView
00181     *image_view;
00182 
00183   CubeInfo
00184     *cube_info;
00185 
00186   MagickBooleanType
00187     proceed;
00188 
00189   PixelInfo
00190     pixel,
00191     target;
00192 
00193   NodeInfo
00194     *node_info;
00195 
00196   register const Quantum
00197     *p;
00198 
00199   register size_t
00200     id,
00201     index,
00202     level;
00203 
00204   register ssize_t
00205     i,
00206     x;
00207 
00208   ssize_t
00209     y;
00210 
00211   /*
00212     Initialize color description tree.
00213   */
00214   assert(image != (const Image *) NULL);
00215   assert(image->signature == MagickSignature);
00216   if (image->debug != MagickFalse)
00217     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00218   cube_info=GetCubeInfo();
00219   if (cube_info == (CubeInfo *) NULL)
00220     {
00221       (void) ThrowMagickException(exception,GetMagickModule(),
00222         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00223       return(cube_info);
00224     }
00225   GetPixelInfo(image,&pixel);
00226   GetPixelInfo(image,&target);
00227   image_view=AcquireCacheView(image);
00228   for (y=0; y < (ssize_t) image->rows; y++)
00229   {
00230     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00231     if (p == (const Quantum *) NULL)
00232       break;
00233     for (x=0; x < (ssize_t) image->columns; x++)
00234     {
00235       /*
00236         Start at the root and proceed level by level.
00237       */
00238       node_info=cube_info->root;
00239       index=MaxTreeDepth-1;
00240       for (level=1; level < MaxTreeDepth; level++)
00241       {
00242         GetPixelInfoPixel(image,p,&pixel);
00243         id=ColorToNodeId(image,&pixel,index);
00244         if (node_info->child[id] == (NodeInfo *) NULL)
00245           {
00246             node_info->child[id]=GetNodeInfo(cube_info,level);
00247             if (node_info->child[id] == (NodeInfo *) NULL)
00248               {
00249                 (void) ThrowMagickException(exception,GetMagickModule(),
00250                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
00251                   image->filename);
00252                 return(0);
00253               }
00254           }
00255         node_info=node_info->child[id];
00256         index--;
00257       }
00258       for (i=0; i < (ssize_t) node_info->number_unique; i++)
00259       {
00260         target=node_info->list[i];
00261         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
00262           break;
00263       }
00264       if (i < (ssize_t) node_info->number_unique)
00265         node_info->list[i].count++;
00266       else
00267         {
00268           if (node_info->number_unique == 0)
00269             node_info->list=(PixelInfo *) AcquireMagickMemory(
00270               sizeof(*node_info->list));
00271           else
00272             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
00273               (size_t) (i+1),sizeof(*node_info->list));
00274           if (node_info->list == (PixelInfo *) NULL)
00275             {
00276               (void) ThrowMagickException(exception,GetMagickModule(),
00277                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
00278                 image->filename);
00279               return(0);
00280             }
00281           node_info->list[i]=pixel;
00282           node_info->list[i].red=GetPixelRed(image,p);
00283           node_info->list[i].green=GetPixelGreen(image,p);
00284           node_info->list[i].blue=GetPixelBlue(image,p);
00285           if (image->colorspace == CMYKColorspace)
00286             node_info->list[i].black=GetPixelBlack(image,p);
00287           node_info->list[i].alpha=GetPixelAlpha(image,p);
00288           node_info->list[i].count=1;
00289           node_info->number_unique++;
00290           cube_info->colors++;
00291         }
00292       p+=GetPixelChannels(image);
00293     }
00294     proceed=SetImageProgress(image,EvaluateImageTag,(MagickOffsetType) y,
00295       image->rows);
00296     if (proceed == MagickFalse)
00297       break;
00298   }
00299   image_view=DestroyCacheView(image_view);
00300   return(cube_info);
00301 }
00302 
00303 /*
00304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00305 %                                                                             %
00306 %                                                                             %
00307 %                                                                             %
00308 +   D e f i n e I m a g e H i s t o g r a m                                   %
00309 %                                                                             %
00310 %                                                                             %
00311 %                                                                             %
00312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00313 %
00314 %  DefineImageHistogram() traverses the color cube tree and notes each colormap
00315 %  entry.  A colormap entry is any node in the color cube tree where the
00316 %  of unique colors is not zero.
00317 %
00318 %  The format of the DefineImageHistogram method is:
00319 %
00320 %      DefineImageHistogram(const Image *image,NodeInfo *node_info,
00321 %        PixelInfo **unique_colors)
00322 %
00323 %  A description of each parameter follows.
00324 %
00325 %    o image: the image.
00326 %
00327 %    o node_info: the address of a structure of type NodeInfo which points to a
00328 %      node in the color cube tree that is to be pruned.
00329 %
00330 %    o histogram: the image histogram.
00331 %
00332 */
00333 static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
00334   PixelInfo **histogram)
00335 {
00336   register ssize_t
00337     i;
00338 
00339   size_t
00340     number_children;
00341 
00342   /*
00343     Traverse any children.
00344   */
00345   number_children=image->matte == MagickFalse ? 8UL : 16UL;
00346   for (i=0; i < (ssize_t) number_children; i++)
00347     if (node_info->child[i] != (NodeInfo *) NULL)
00348       DefineImageHistogram(image,node_info->child[i],histogram);
00349   if (node_info->level == (MaxTreeDepth-1))
00350     {
00351       register PixelInfo
00352         *p;
00353 
00354       p=node_info->list;
00355       for (i=0; i < (ssize_t) node_info->number_unique; i++)
00356       {
00357         **histogram=(*p);
00358         (*histogram)++;
00359         p++;
00360       }
00361     }
00362 }
00363 
00364 /*
00365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00366 %                                                                             %
00367 %                                                                             %
00368 %                                                                             %
00369 +   D e s t r o y C u b e I n f o                                             %
00370 %                                                                             %
00371 %                                                                             %
00372 %                                                                             %
00373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00374 %
00375 %  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
00376 %
00377 %  The format of the DestroyCubeInfo method is:
00378 %
00379 %      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
00380 %
00381 %  A description of each parameter follows:
00382 %
00383 %    o image: the image.
00384 %
00385 %    o cube_info: the address of a structure of type CubeInfo.
00386 %
00387 */
00388 static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
00389 {
00390   register Nodes
00391     *nodes;
00392 
00393   /*
00394     Release color cube tree storage.
00395   */
00396   DestroyColorCube(image,cube_info->root);
00397   do
00398   {
00399     nodes=cube_info->node_queue->next;
00400     cube_info->node_queue=(Nodes *)
00401       RelinquishMagickMemory(cube_info->node_queue);
00402     cube_info->node_queue=nodes;
00403   } while (cube_info->node_queue != (Nodes *) NULL);
00404   return((CubeInfo *) RelinquishMagickMemory(cube_info));
00405 }
00406 
00407 /*
00408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00409 %                                                                             %
00410 %                                                                             %
00411 %                                                                             %
00412 +  D e s t r o y C o l o r C u b e                                            %
00413 %                                                                             %
00414 %                                                                             %
00415 %                                                                             %
00416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00417 %
00418 %  DestroyColorCube() traverses the color cube tree and frees the list of
00419 %  unique colors.
00420 %
00421 %  The format of the DestroyColorCube method is:
00422 %
00423 %      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
00424 %
00425 %  A description of each parameter follows.
00426 %
00427 %    o image: the image.
00428 %
00429 %    o node_info: the address of a structure of type NodeInfo which points to a
00430 %      node in the color cube tree that is to be pruned.
00431 %
00432 */
00433 static void DestroyColorCube(const Image *image,NodeInfo *node_info)
00434 {
00435   register ssize_t
00436     i;
00437 
00438   size_t
00439     number_children;
00440 
00441   /*
00442     Traverse any children.
00443   */
00444   number_children=image->matte == MagickFalse ? 8UL : 16UL;
00445   for (i=0; i < (ssize_t) number_children; i++)
00446     if (node_info->child[i] != (NodeInfo *) NULL)
00447       DestroyColorCube(image,node_info->child[i]);
00448   if (node_info->list != (PixelInfo *) NULL)
00449     node_info->list=(PixelInfo *) RelinquishMagickMemory(node_info->list);
00450 }
00451 
00452 /*
00453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00454 %                                                                             %
00455 %                                                                             %
00456 %                                                                             %
00457 +   G e t C u b e I n f o                                                     %
00458 %                                                                             %
00459 %                                                                             %
00460 %                                                                             %
00461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00462 %
00463 %  GetCubeInfo() initializes the CubeInfo data structure.
00464 %
00465 %  The format of the GetCubeInfo method is:
00466 %
00467 %      cube_info=GetCubeInfo()
00468 %
00469 %  A description of each parameter follows.
00470 %
00471 %    o cube_info: A pointer to the Cube structure.
00472 %
00473 */
00474 static CubeInfo *GetCubeInfo(void)
00475 {
00476   CubeInfo
00477     *cube_info;
00478 
00479   /*
00480     Initialize tree to describe color cube.
00481   */
00482   cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
00483   if (cube_info == (CubeInfo *) NULL)
00484     return((CubeInfo *) NULL);
00485   (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
00486   /*
00487     Initialize root node.
00488   */
00489   cube_info->root=GetNodeInfo(cube_info,0);
00490   if (cube_info->root == (NodeInfo *) NULL)
00491     return((CubeInfo *) NULL);
00492   return(cube_info);
00493 }
00494 
00495 /*
00496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00497 %                                                                             %
00498 %                                                                             %
00499 %                                                                             %
00500 %  G e t I m a g e H i s t o g r a m                                          %
00501 %                                                                             %
00502 %                                                                             %
00503 %                                                                             %
00504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00505 %
00506 %  GetImageHistogram() returns the unique colors in an image.
00507 %
00508 %  The format of the GetImageHistogram method is:
00509 %
00510 %      size_t GetImageHistogram(const Image *image,
00511 %        size_t *number_colors,ExceptionInfo *exception)
00512 %
00513 %  A description of each parameter follows.
00514 %
00515 %    o image: the image.
00516 %
00517 %    o file:  Write a histogram of the color distribution to this file handle.
00518 %
00519 %    o exception: return any errors or warnings in this structure.
00520 %
00521 */
00522 MagickExport PixelInfo *GetImageHistogram(const Image *image,
00523   size_t *number_colors,ExceptionInfo *exception)
00524 {
00525   PixelInfo
00526     *histogram;
00527 
00528   CubeInfo
00529     *cube_info;
00530 
00531   *number_colors=0;
00532   histogram=(PixelInfo *) NULL;
00533   cube_info=ClassifyImageColors(image,exception);
00534   if (cube_info != (CubeInfo *) NULL)
00535     {
00536       histogram=(PixelInfo *) AcquireQuantumMemory((size_t) cube_info->colors,
00537         sizeof(*histogram));
00538       if (histogram == (PixelInfo *) NULL)
00539         (void) ThrowMagickException(exception,GetMagickModule(),
00540           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00541       else
00542         {
00543           PixelInfo
00544             *root;
00545 
00546           *number_colors=cube_info->colors;
00547           root=histogram;
00548           DefineImageHistogram(image,cube_info->root,&root);
00549         }
00550     }
00551   cube_info=DestroyCubeInfo(image,cube_info);
00552   return(histogram);
00553 }
00554 
00555 /*
00556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00557 %                                                                             %
00558 %                                                                             %
00559 %                                                                             %
00560 +  G e t N o d e I n f o                                                      %
00561 %                                                                             %
00562 %                                                                             %
00563 %                                                                             %
00564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00565 %
00566 %  GetNodeInfo() allocates memory for a new node in the color cube tree and
00567 %  presets all fields to zero.
00568 %
00569 %  The format of the GetNodeInfo method is:
00570 %
00571 %      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
00572 %
00573 %  A description of each parameter follows.
00574 %
00575 %    o cube_info: A pointer to the CubeInfo structure.
00576 %
00577 %    o level: Specifies the level in the storage_class the node resides.
00578 %
00579 */
00580 static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
00581 {
00582   NodeInfo
00583     *node_info;
00584 
00585   if (cube_info->free_nodes == 0)
00586     {
00587       Nodes
00588         *nodes;
00589 
00590       /*
00591         Allocate a new nodes of nodes.
00592       */
00593       nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
00594       if (nodes == (Nodes *) NULL)
00595         return((NodeInfo *) NULL);
00596       nodes->next=cube_info->node_queue;
00597       cube_info->node_queue=nodes;
00598       cube_info->node_info=nodes->nodes;
00599       cube_info->free_nodes=NodesInAList;
00600     }
00601   cube_info->free_nodes--;
00602   node_info=cube_info->node_info++;
00603   (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
00604   node_info->level=level;
00605   return(node_info);
00606 }
00607 
00608 /*
00609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00610 %                                                                             %
00611 %                                                                             %
00612 %                                                                             %
00613 %  I s H i s t o g r a m I m a g e                                            %
00614 %                                                                             %
00615 %                                                                             %
00616 %                                                                             %
00617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00618 %
00619 %  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
00620 %  less.
00621 %
00622 %  The format of the IsHistogramImage method is:
00623 %
00624 %      MagickBooleanType IsHistogramImage(const Image *image,
00625 %        ExceptionInfo *exception)
00626 %
00627 %  A description of each parameter follows.
00628 %
00629 %    o image: the image.
00630 %
00631 %    o exception: return any errors or warnings in this structure.
00632 %
00633 */
00634 MagickExport MagickBooleanType IsHistogramImage(const Image *image,
00635   ExceptionInfo *exception)
00636 {
00637 #define MaximumUniqueColors  1024
00638 
00639   CacheView
00640     *image_view;
00641 
00642   CubeInfo
00643     *cube_info;
00644 
00645   PixelInfo
00646     pixel,
00647     target;
00648 
00649   register const Quantum
00650     *p;
00651 
00652   register ssize_t
00653     x;
00654 
00655   register NodeInfo
00656     *node_info;
00657 
00658   register ssize_t
00659     i;
00660 
00661   size_t
00662     id,
00663     index,
00664     level;
00665 
00666   ssize_t
00667     y;
00668 
00669   assert(image != (Image *) NULL);
00670   assert(image->signature == MagickSignature);
00671   if (image->debug != MagickFalse)
00672     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00673   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
00674     return(MagickTrue);
00675   if (image->storage_class == PseudoClass)
00676     return(MagickFalse);
00677   /*
00678     Initialize color description tree.
00679   */
00680   cube_info=GetCubeInfo();
00681   if (cube_info == (CubeInfo *) NULL)
00682     {
00683       (void) ThrowMagickException(exception,GetMagickModule(),
00684         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00685       return(MagickFalse);
00686     }
00687   GetPixelInfo(image,&pixel);
00688   GetPixelInfo(image,&target);
00689   image_view=AcquireCacheView(image);
00690   for (y=0; y < (ssize_t) image->rows; y++)
00691   {
00692     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00693     if (p == (const Quantum *) NULL)
00694       break;
00695     for (x=0; x < (ssize_t) image->columns; x++)
00696     {
00697       /*
00698         Start at the root and proceed level by level.
00699       */
00700       node_info=cube_info->root;
00701       index=MaxTreeDepth-1;
00702       for (level=1; level < MaxTreeDepth; level++)
00703       {
00704         GetPixelInfoPixel(image,p,&pixel);
00705         id=ColorToNodeId(image,&pixel,index);
00706         if (node_info->child[id] == (NodeInfo *) NULL)
00707           {
00708             node_info->child[id]=GetNodeInfo(cube_info,level);
00709             if (node_info->child[id] == (NodeInfo *) NULL)
00710               {
00711                 (void) ThrowMagickException(exception,GetMagickModule(),
00712                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
00713                   image->filename);
00714                 break;
00715               }
00716           }
00717         node_info=node_info->child[id];
00718         index--;
00719       }
00720       if (level < MaxTreeDepth)
00721         break;
00722       for (i=0; i < (ssize_t) node_info->number_unique; i++)
00723       {
00724         target=node_info->list[i];
00725         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
00726           break;
00727       }
00728       if (i < (ssize_t) node_info->number_unique)
00729         node_info->list[i].count++;
00730       else
00731         {
00732           /*
00733             Add this unique color to the color list.
00734           */
00735           if (node_info->number_unique == 0)
00736             node_info->list=(PixelInfo *) AcquireMagickMemory(
00737               sizeof(*node_info->list));
00738           else
00739             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
00740               (size_t) (i+1),sizeof(*node_info->list));
00741           if (node_info->list == (PixelInfo *) NULL)
00742             {
00743               (void) ThrowMagickException(exception,GetMagickModule(),
00744                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
00745                 image->filename);
00746               break;
00747             }
00748           node_info->list[i].red=GetPixelRed(image,p);
00749           node_info->list[i].green=GetPixelGreen(image,p);
00750           node_info->list[i].blue=GetPixelBlue(image,p);
00751           if (image->colorspace == CMYKColorspace)
00752             node_info->list[i].black=GetPixelBlack(image,p);
00753           node_info->list[i].alpha=GetPixelAlpha(image,p);
00754           node_info->list[i].count=1;
00755           node_info->number_unique++;
00756           cube_info->colors++;
00757           if (cube_info->colors > MaximumUniqueColors)
00758             break;
00759         }
00760       p+=GetPixelChannels(image);
00761     }
00762     if (x < (ssize_t) image->columns)
00763       break;
00764   }
00765   image_view=DestroyCacheView(image_view);
00766   cube_info=DestroyCubeInfo(image,cube_info);
00767   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
00768 }
00769 
00770 /*
00771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00772 %                                                                             %
00773 %                                                                             %
00774 %                                                                             %
00775 %  I s P a l e t t e I m a g e                                                %
00776 %                                                                             %
00777 %                                                                             %
00778 %                                                                             %
00779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00780 %
00781 %  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
00782 %  unique colors or less.
00783 %
00784 %  The format of the IsPaletteImage method is:
00785 %
00786 %      MagickBooleanType IsPaletteImage(const Image *image,
00787 %        ExceptionInfo *exception)
00788 %
00789 %  A description of each parameter follows.
00790 %
00791 %    o image: the image.
00792 %
00793 %    o exception: return any errors or warnings in this structure.
00794 %
00795 */
00796 MagickExport MagickBooleanType IsPaletteImage(const Image *image,
00797   ExceptionInfo *exception)
00798 {
00799   CacheView
00800     *image_view;
00801 
00802   CubeInfo
00803     *cube_info;
00804 
00805   PixelInfo
00806     pixel,
00807     target;
00808 
00809   register const Quantum
00810     *p;
00811 
00812   register ssize_t
00813     x;
00814 
00815   register NodeInfo
00816     *node_info;
00817 
00818   register ssize_t
00819     i;
00820 
00821   size_t
00822     id,
00823     index,
00824     level;
00825 
00826   ssize_t
00827     y;
00828 
00829   assert(image != (Image *) NULL);
00830   assert(image->signature == MagickSignature);
00831   if (image->debug != MagickFalse)
00832     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00833   if ((image->storage_class == PseudoClass) && (image->colors <= 256))
00834     return(MagickTrue);
00835   if (image->storage_class == PseudoClass)
00836     return(MagickFalse);
00837   /*
00838     Initialize color description tree.
00839   */
00840   cube_info=GetCubeInfo();
00841   if (cube_info == (CubeInfo *) NULL)
00842     {
00843       (void) ThrowMagickException(exception,GetMagickModule(),
00844         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00845       return(MagickFalse);
00846     }
00847   GetPixelInfo(image,&pixel);
00848   GetPixelInfo(image,&target);
00849   image_view=AcquireCacheView(image);
00850   for (y=0; y < (ssize_t) image->rows; y++)
00851   {
00852     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00853     if (p == (const Quantum *) NULL)
00854       break;
00855     for (x=0; x < (ssize_t) image->columns; x++)
00856     {
00857       /*
00858         Start at the root and proceed level by level.
00859       */
00860       node_info=cube_info->root;
00861       index=MaxTreeDepth-1;
00862       for (level=1; level < MaxTreeDepth; level++)
00863       {
00864         GetPixelInfoPixel(image,p,&pixel);
00865         id=ColorToNodeId(image,&pixel,index);
00866         if (node_info->child[id] == (NodeInfo *) NULL)
00867           {
00868             node_info->child[id]=GetNodeInfo(cube_info,level);
00869             if (node_info->child[id] == (NodeInfo *) NULL)
00870               {
00871                 (void) ThrowMagickException(exception,GetMagickModule(),
00872                   ResourceLimitError,"MemoryAllocationFailed","`%s'",
00873                   image->filename);
00874                 break;
00875               }
00876           }
00877         node_info=node_info->child[id];
00878         index--;
00879       }
00880       if (level < MaxTreeDepth)
00881         break;
00882       for (i=0; i < (ssize_t) node_info->number_unique; i++)
00883       {
00884         target=node_info->list[i];
00885         if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
00886           break;
00887       }
00888       if (i < (ssize_t) node_info->number_unique)
00889         node_info->list[i].count++;
00890       else
00891         {
00892           /*
00893             Add this unique color to the color list.
00894           */
00895           if (node_info->number_unique == 0)
00896             node_info->list=(PixelInfo *) AcquireMagickMemory(
00897               sizeof(*node_info->list));
00898           else
00899             node_info->list=(PixelInfo *) ResizeQuantumMemory(node_info->list,
00900               (size_t) (i+1),sizeof(*node_info->list));
00901           if (node_info->list == (PixelInfo *) NULL)
00902             {
00903               (void) ThrowMagickException(exception,GetMagickModule(),
00904                 ResourceLimitError,"MemoryAllocationFailed","`%s'",
00905                 image->filename);
00906               break;
00907             }
00908           node_info->list[i]=pixel;
00909           node_info->list[i].red=GetPixelRed(image,p);
00910           node_info->list[i].green=GetPixelGreen(image,p);
00911           node_info->list[i].blue=GetPixelBlue(image,p);
00912           if (image->colorspace == CMYKColorspace)
00913             node_info->list[i].black=GetPixelBlack(image,p);
00914           node_info->list[i].alpha=GetPixelAlpha(image,p);
00915           node_info->list[i].count=1;
00916           node_info->number_unique++;
00917           cube_info->colors++;
00918           if (cube_info->colors > 256)
00919             break;
00920         }
00921       p+=GetPixelChannels(image);
00922     }
00923     if (x < (ssize_t) image->columns)
00924       break;
00925   }
00926   image_view=DestroyCacheView(image_view);
00927   cube_info=DestroyCubeInfo(image,cube_info);
00928   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
00929 }
00930 
00931 /*
00932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00933 %                                                                             %
00934 %                                                                             %
00935 %                                                                             %
00936 %     M i n M a x S t r e t c h I m a g e                                     %
00937 %                                                                             %
00938 %                                                                             %
00939 %                                                                             %
00940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00941 %
00942 %  MinMaxStretchImage() uses the exact minimum and maximum values found in
00943 %  each of the channels given, as the BlackPoint and WhitePoint to linearly
00944 %  stretch the colors (and histogram) of the image.  The stretch points are
00945 %  also moved further inward by the adjustment values given.
00946 %
00947 %  If the adjustment values are both zero this function is equivalent to a
00948 %  perfect normalization (or autolevel) of the image.
00949 %
00950 %  Each channel is stretched independantally of each other (producing color
00951 %  distortion) unless the special 'SyncChannels' flag is also provided in the
00952 %  channels setting. If this flag is present the minimum and maximum point
00953 %  will be extracted from all the given channels, and those channels will be
00954 %  stretched by exactly the same amount (preventing color distortion).
00955 %
00956 %  In the special case that only ONE value is found in a channel of the image
00957 %  that value is not stretched, that value is left as is.
00958 %
00959 %  The 'SyncChannels' is turned on in the 'DefaultChannels' setting by
00960 %  default.
00961 %
00962 %  The format of the MinMaxStretchImage method is:
00963 %
00964 %      MagickBooleanType MinMaxStretchImage(Image *image,const double black,
00965 %        const double white,const double gamma,ExceptionInfo *exception)
00966 %
00967 %  A description of each parameter follows:
00968 %
00969 %    o image: The image to auto-level
00970 %
00971 %    o black, white:  move the black / white point inward from the minimum and
00972 %      maximum points by this color value.
00973 %
00974 %    o gamma: the gamma.
00975 %
00976 %    o exception: return any errors or warnings in this structure.
00977 %
00978 */
00979 MagickExport MagickBooleanType MinMaxStretchImage(Image *image,
00980   const double black,const double white,const double gamma,
00981   ExceptionInfo *exception)
00982 {
00983   double
00984     min,
00985     max;
00986 
00987   register ssize_t
00988     i;
00989 
00990   MagickStatusType
00991     status;
00992 
00993   status=MagickTrue;
00994   if (image->channel_mask == DefaultChannels)
00995     {
00996       /*
00997         Auto-level all channels equally.
00998       */
00999       (void) GetImageRange(image,&min,&max,exception);
01000       min+=black;
01001       max-=white;
01002       if (fabs(min-max) >= MagickEpsilon)
01003         status&=LevelImage(image,min,max,gamma,exception);
01004       return(status != 0 ? MagickTrue : MagickFalse);
01005     }
01006   /*
01007     Auto-level each channel separately.
01008   */
01009   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01010   {
01011     ChannelType
01012       channel_mask;
01013 
01014     PixelChannel
01015       channel;
01016 
01017     PixelTrait
01018       traits;
01019 
01020     channel=GetPixelChannelMapChannel(image,i);
01021     traits=GetPixelChannelMapTraits(image,channel);
01022     if ((traits & UpdatePixelTrait) == 0)
01023       continue;
01024     channel_mask=SetPixelChannelMask(image,(ChannelType) (1 << i));
01025     status&=GetImageRange(image,&min,&max,exception);
01026     min+=black;
01027     max-=white;
01028     if (fabs(min-max) >= MagickEpsilon)
01029       status&=LevelImage(image,min,max,gamma,exception);
01030     (void) SetPixelChannelMask(image,channel_mask);
01031   }
01032   return(status != 0 ? MagickTrue : MagickFalse);
01033 }
01034 
01035 /*
01036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01037 %                                                                             %
01038 %                                                                             %
01039 %                                                                             %
01040 %  G e t N u m b e r C o l o r s                                              %
01041 %                                                                             %
01042 %                                                                             %
01043 %                                                                             %
01044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01045 %
01046 %  GetNumberColors() returns the number of unique colors in an image.
01047 %
01048 %  The format of the GetNumberColors method is:
01049 %
01050 %      size_t GetNumberColors(const Image *image,FILE *file,
01051 %        ExceptionInfo *exception)
01052 %
01053 %  A description of each parameter follows.
01054 %
01055 %    o image: the image.
01056 %
01057 %    o file:  Write a histogram of the color distribution to this file handle.
01058 %
01059 %    o exception: return any errors or warnings in this structure.
01060 %
01061 */
01062 
01063 #if defined(__cplusplus) || defined(c_plusplus)
01064 extern "C" {
01065 #endif
01066 
01067 static int HistogramCompare(const void *x,const void *y)
01068 {
01069   const PixelInfo
01070     *color_1,
01071     *color_2;
01072 
01073   color_1=(const PixelInfo *) x;
01074   color_2=(const PixelInfo *) y;
01075   if (color_2->red != color_1->red)
01076     return((int) color_1->red-(int) color_2->red);
01077   if (color_2->green != color_1->green)
01078     return((int) color_1->green-(int) color_2->green);
01079   if (color_2->blue != color_1->blue)
01080     return((int) color_1->blue-(int) color_2->blue);
01081   return((int) color_2->count-(int) color_1->count);
01082 }
01083 
01084 #if defined(__cplusplus) || defined(c_plusplus)
01085 }
01086 #endif
01087 
01088 MagickExport size_t GetNumberColors(const Image *image,FILE *file,
01089   ExceptionInfo *exception)
01090 {
01091 #define HistogramImageTag  "Histogram/Image"
01092 
01093   char
01094     color[MaxTextExtent],
01095     hex[MaxTextExtent],
01096     tuple[MaxTextExtent];
01097 
01098   PixelInfo
01099     *histogram;
01100 
01101   MagickBooleanType
01102     status;
01103 
01104   PixelInfo
01105     pixel;
01106 
01107   register PixelInfo
01108     *p;
01109 
01110   register ssize_t
01111     i;
01112 
01113   size_t
01114     number_colors;
01115 
01116   number_colors=0;
01117   if (file == (FILE *) NULL)
01118     {
01119       CubeInfo
01120         *cube_info;
01121 
01122       cube_info=ClassifyImageColors(image,exception);
01123       if (cube_info != (CubeInfo *) NULL)
01124         number_colors=cube_info->colors;
01125       cube_info=DestroyCubeInfo(image,cube_info);
01126       return(number_colors);
01127     }
01128   histogram=GetImageHistogram(image,&number_colors,exception);
01129   if (histogram == (PixelInfo *) NULL)
01130     return(number_colors);
01131   qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
01132     HistogramCompare);
01133   GetPixelInfo(image,&pixel);
01134   p=histogram;
01135   status=MagickTrue;
01136   for (i=0; i < (ssize_t) number_colors; i++)
01137   {
01138     pixel=(*p);
01139     (void) CopyMagickString(tuple,"(",MaxTextExtent);
01140     ConcatenateColorComponent(&pixel,RedPixelChannel,X11Compliance,tuple);
01141     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
01142     ConcatenateColorComponent(&pixel,GreenPixelChannel,X11Compliance,tuple);
01143     (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
01144     ConcatenateColorComponent(&pixel,BluePixelChannel,X11Compliance,tuple);
01145     if (pixel.colorspace == CMYKColorspace)
01146       {
01147         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
01148         ConcatenateColorComponent(&pixel,BlackPixelChannel,X11Compliance,
01149           tuple);
01150       }
01151     if (pixel.matte != MagickFalse)
01152       {
01153         (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
01154         ConcatenateColorComponent(&pixel,AlphaPixelChannel,X11Compliance,
01155           tuple);
01156       }
01157     (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
01158     (void) QueryColorname(image,&pixel,SVGCompliance,color,exception);
01159     GetColorTuple(&pixel,MagickTrue,hex);
01160     (void) FormatLocaleFile(file,"%10" MagickSizeFormat,p->count);
01161     (void) FormatLocaleFile(file,": %s %s %s\n",tuple,hex,color);
01162     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01163       {
01164         MagickBooleanType
01165           proceed;
01166 
01167         proceed=SetImageProgress(image,HistogramImageTag,(MagickOffsetType) i,
01168           number_colors);
01169         if (proceed == MagickFalse)
01170           status=MagickFalse;
01171       }
01172     p++;
01173   }
01174   (void) fflush(file);
01175   histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
01176   if (status == MagickFalse)
01177     return(0);
01178   return(number_colors);
01179 }
01180 
01181 /*
01182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01183 %                                                                             %
01184 %                                                                             %
01185 %                                                                             %
01186 %  U n i q u e I m a g e C o l o r s                                          %
01187 %                                                                             %
01188 %                                                                             %
01189 %                                                                             %
01190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01191 %
01192 %  UniqueImageColors() returns the unique colors of an image.
01193 %
01194 %  The format of the UniqueImageColors method is:
01195 %
01196 %      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
01197 %
01198 %  A description of each parameter follows.
01199 %
01200 %    o image: the image.
01201 %
01202 %    o exception: return any errors or warnings in this structure.
01203 %
01204 */
01205 
01206 static void UniqueColorsToImage(Image *unique_image,CacheView *unique_view,
01207   CubeInfo *cube_info,const NodeInfo *node_info,ExceptionInfo *exception)
01208 {
01209 #define UniqueColorsImageTag  "UniqueColors/Image"
01210 
01211   MagickBooleanType
01212     status;
01213 
01214   register ssize_t
01215     i;
01216 
01217   size_t
01218     number_children;
01219 
01220   /*
01221     Traverse any children.
01222   */
01223   number_children=unique_image->matte == MagickFalse ? 8UL : 16UL;
01224   for (i=0; i < (ssize_t) number_children; i++)
01225     if (node_info->child[i] != (NodeInfo *) NULL)
01226       UniqueColorsToImage(unique_image,unique_view,cube_info,
01227         node_info->child[i],exception);
01228   if (node_info->level == (MaxTreeDepth-1))
01229     {
01230       register PixelInfo
01231         *p;
01232 
01233       register Quantum
01234         *restrict q;
01235 
01236       status=MagickTrue;
01237       p=node_info->list;
01238       for (i=0; i < (ssize_t) node_info->number_unique; i++)
01239       {
01240         q=QueueCacheViewAuthenticPixels(unique_view,cube_info->x,0,1,1,
01241           exception);
01242         if (q == (Quantum *) NULL)
01243           continue;
01244         SetPixelRed(unique_image,p->red,q);
01245         SetPixelGreen(unique_image,p->green,q);
01246         SetPixelBlue(unique_image,p->blue,q);
01247         SetPixelAlpha(unique_image,p->alpha,q);
01248         if (unique_image->colorspace == CMYKColorspace)
01249           SetPixelBlack(unique_image,p->black,q);
01250         if (SyncCacheViewAuthenticPixels(unique_view,exception) == MagickFalse)
01251           break;
01252         cube_info->x++;
01253         p++;
01254       }
01255       if (unique_image->progress_monitor != (MagickProgressMonitor) NULL)
01256         {
01257           MagickBooleanType
01258             proceed;
01259 
01260           proceed=SetImageProgress(unique_image,UniqueColorsImageTag,
01261             cube_info->progress,cube_info->colors);
01262           if (proceed == MagickFalse)
01263             status=MagickFalse;
01264         }
01265       cube_info->progress++;
01266       if (status == MagickFalse)
01267         return;
01268     }
01269 }
01270 
01271 MagickExport Image *UniqueImageColors(const Image *image,
01272   ExceptionInfo *exception)
01273 {
01274   CacheView
01275     *unique_view;
01276 
01277   CubeInfo
01278     *cube_info;
01279 
01280   Image
01281     *unique_image;
01282 
01283   cube_info=ClassifyImageColors(image,exception);
01284   if (cube_info == (CubeInfo *) NULL)
01285     return((Image *) NULL);
01286   unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
01287   if (unique_image == (Image *) NULL)
01288     return(unique_image);
01289   if (SetImageStorageClass(unique_image,DirectClass,exception) == MagickFalse)
01290     {
01291       unique_image=DestroyImage(unique_image);
01292       return((Image *) NULL);
01293     }
01294   unique_view=AcquireCacheView(unique_image);
01295   UniqueColorsToImage(unique_image,unique_view,cube_info,cube_info->root,
01296     exception);
01297   unique_view=DestroyCacheView(unique_view);
01298   if (cube_info->colors < MaxColormapSize)
01299     {
01300       QuantizeInfo
01301         *quantize_info;
01302 
01303       quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
01304       quantize_info->number_colors=MaxColormapSize;
01305       quantize_info->dither=MagickFalse;
01306       quantize_info->tree_depth=8;
01307       (void) QuantizeImage(quantize_info,unique_image,exception);
01308       quantize_info=DestroyQuantizeInfo(quantize_info);
01309     }
01310   cube_info=DestroyCubeInfo(image,cube_info);
01311   return(unique_image);
01312 }