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

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1