From f2e1166e90de2dfe2e6a2aed7cd5f73640f34a7a Mon Sep 17 00:00:00 2001 From: cristy Date: Wed, 14 Oct 2009 01:24:43 +0000 Subject: [PATCH] --- coders/ept.c | 1 + coders/histogram.c | 1 + coders/map.c | 1 + coders/palm.c | 1 + coders/png.c | 1 + config/configure.xml | 2 +- magick/cache.c | 2 +- magick/color.c | 1125 +-------------------------------------- magick/color.h | 23 - magick/histogram.c | 1186 +++++++++++++++++++++++++++++++++++++++++- magick/histogram.h | 23 + magick/identify.c | 1 + magick/image.c | 3 +- magick/magick.c | 1 + magick/property.c | 2 + magick/quantize.c | 1 + magick/version.h | 4 +- 17 files changed, 1203 insertions(+), 1175 deletions(-) diff --git a/coders/ept.c b/coders/ept.c index af97f0898..3aaf96909 100644 --- a/coders/ept.c +++ b/coders/ept.c @@ -49,6 +49,7 @@ #include "magick/exception-private.h" #include "magick/delegate.h" #include "magick/geometry.h" +#include "magick/histogram.h" #include "magick/image.h" #include "magick/image-private.h" #include "magick/list.h" diff --git a/coders/histogram.c b/coders/histogram.c index ac2a3d017..b416772de 100644 --- a/coders/histogram.c +++ b/coders/histogram.c @@ -50,6 +50,7 @@ #include "magick/exception.h" #include "magick/exception-private.h" #include "magick/geometry.h" +#include "magick/histogram.h" #include "magick/image-private.h" #include "magick/magick.h" #include "magick/memory_.h" diff --git a/coders/map.c b/coders/map.c index d1d399e32..1949b1042 100644 --- a/coders/map.c +++ b/coders/map.c @@ -49,6 +49,7 @@ #include "magick/colorspace.h" #include "magick/exception.h" #include "magick/exception-private.h" +#include "magick/histogram.h" #include "magick/image.h" #include "magick/image-private.h" #include "magick/list.h" diff --git a/coders/palm.c b/coders/palm.c index 481f8be26..87a968ba0 100644 --- a/coders/palm.c +++ b/coders/palm.c @@ -52,6 +52,7 @@ #include "magick/colorspace.h" #include "magick/constitute.h" #include "magick/exception.h" +#include "magick/histogram.h" #include "magick/image.h" #include "magick/list.h" #include "magick/magick.h" diff --git a/coders/png.c b/coders/png.c index 00664ff11..63ec3fe97 100644 --- a/coders/png.c +++ b/coders/png.c @@ -53,6 +53,7 @@ #include "magick/exception.h" #include "magick/exception-private.h" #include "magick/geometry.h" +#include "magick/histogram.h" #include "magick/image.h" #include "magick/image-private.h" #include "magick/layer.h" diff --git a/config/configure.xml b/config/configure.xml index 03693e657..47cb8b43a 100644 --- a/config/configure.xml +++ b/config/configure.xml @@ -9,7 +9,7 @@ - + diff --git a/magick/cache.c b/magick/cache.c index 48e2ce8d2..89fdcad01 100644 --- a/magick/cache.c +++ b/magick/cache.c @@ -2132,7 +2132,7 @@ MagickExport Cache GetImagePixelCache(Image *image, } (void) UnlockSemaphoreInfo(cache_info->semaphore); if (destroy != MagickFalse) - cache_info=DestroyPixelCache(cache_info); + cache_info=(CacheInfo *) DestroyPixelCache(cache_info); if (status != MagickFalse) { /* diff --git a/magick/color.c b/magick/color.c index 65e3ee5d0..8c054b874 100644 --- a/magick/color.c +++ b/magick/color.c @@ -70,8 +70,6 @@ Define declarations. */ #define ColorFilename "colors.xml" -#define MaxTreeDepth 8 -#define NodesInAList 1536 /* Declare color map. @@ -336,53 +334,6 @@ static const char " " ""; -/* - Typedef declarations. -*/ -typedef struct _NodeInfo -{ - struct _NodeInfo - *child[16]; - - ColorPacket - *list; - - MagickSizeType - number_unique; - - unsigned long - level; -} NodeInfo; - -typedef struct _Nodes -{ - NodeInfo - nodes[NodesInAList]; - - struct _Nodes - *next; -} Nodes; - -typedef struct _CubeInfo -{ - NodeInfo - *root; - - long - x, - progress; - - unsigned long - colors, - free_nodes; - - NodeInfo - *node_info; - - Nodes - *node_queue; -} CubeInfo; - /* Static declarations. */ @@ -398,191 +349,9 @@ static volatile MagickBooleanType /* Forward declarations. */ -static CubeInfo - *GetCubeInfo(void); - -static NodeInfo - *GetNodeInfo(CubeInfo *,const unsigned long); - static MagickBooleanType InitializeColorList(ExceptionInfo *), LoadColorLists(const char *,ExceptionInfo *); - -static void - DestroyColorCube(const Image *,NodeInfo *); - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -+ C l a s s i f y I m a g e C o l o r s % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% ClassifyImageColors() builds a populated CubeInfo tree for the specified -% image. The returned tree should be deallocated using DestroyCubeInfo() -% once it is no longer needed. -% -% The format of the ClassifyImageColors() method is: -% -% CubeInfo *ClassifyImageColors(const Image *image, -% ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o exception: return any errors or warnings in this structure. -% -*/ - -static inline unsigned long ColorToNodeId(const Image *image, - const MagickPixelPacket *pixel,unsigned long index) -{ - unsigned long - id; - - id=(unsigned long) ( - ((ScaleQuantumToChar(RoundToQuantum(pixel->red)) >> index) & 0x01) | - ((ScaleQuantumToChar(RoundToQuantum(pixel->green)) >> index) & 0x01) << 1 | - ((ScaleQuantumToChar(RoundToQuantum(pixel->blue)) >> index) & 0x01) << 2); - if (image->matte != MagickFalse) - id|=((ScaleQuantumToChar(RoundToQuantum(pixel->opacity)) >> index) & - 0x01) << 3; - return(id); -} - -static CubeInfo *ClassifyImageColors(const Image *image, - ExceptionInfo *exception) -{ -#define EvaluateImageTag " Compute image colors... " - - CubeInfo - *cube_info; - - long - y; - - MagickBooleanType - proceed; - - MagickPixelPacket - pixel, - target; - - NodeInfo - *node_info; - - register const IndexPacket - *indexes; - - register const PixelPacket - *p; - - register long - i, - x; - - register unsigned long - id, - index, - level; - - CacheView - *image_view; - - /* - Initialize color description tree. - */ - assert(image != (const Image *) NULL); - assert(image->signature == MagickSignature); - if (image->debug != MagickFalse) - (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); - cube_info=GetCubeInfo(); - if (cube_info == (CubeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); - return(cube_info); - } - GetMagickPixelPacket(image,&pixel); - GetMagickPixelPacket(image,&target); - image_view=AcquireCacheView(image); - for (y=0; y < (long) image->rows; y++) - { - p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); - if (p == (const PixelPacket *) NULL) - break; - indexes=GetCacheViewVirtualIndexQueue(image_view); - for (x=0; x < (long) image->columns; x++) - { - /* - Start at the root and proceed level by level. - */ - node_info=cube_info->root; - index=MaxTreeDepth-1; - for (level=1; level < MaxTreeDepth; level++) - { - SetMagickPixelPacket(image,p,indexes+x,&pixel); - id=ColorToNodeId(image,&pixel,index); - if (node_info->child[id] == (NodeInfo *) NULL) - { - node_info->child[id]=GetNodeInfo(cube_info,level); - if (node_info->child[id] == (NodeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - return(0); - } - } - node_info=node_info->child[id]; - index--; - } - for (i=0; i < (long) node_info->number_unique; i++) - { - SetMagickPixelPacket(image,&node_info->list[i].pixel, - &node_info->list[i].index,&target); - if (IsMagickColorEqual(&pixel,&target) != MagickFalse) - break; - } - if (i < (long) node_info->number_unique) - node_info->list[i].count++; - else - { - if (node_info->number_unique == 0) - node_info->list=(ColorPacket *) AcquireMagickMemory( - sizeof(*node_info->list)); - else - node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, - (size_t) (i+1),sizeof(*node_info->list)); - if (node_info->list == (ColorPacket *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - return(0); - } - node_info->list[i].pixel=(*p); - if ((image->colorspace == CMYKColorspace) || - (image->storage_class == PseudoClass)) - node_info->list[i].index=indexes[x]; - node_info->list[i].count=1; - node_info->number_unique++; - cube_info->colors++; - } - p++; - } - proceed=SetImageProgress(image,EvaluateImageTag,y,image->rows); - if (proceed == MagickFalse) - break; - } - image_view=DestroyCacheView(image_view); - return(cube_info); -} /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -698,69 +467,6 @@ MagickExport void ConcatenateColorComponent(const MagickPixelPacket *pixel, % % % % % % -+ D e f i n e I m a g e H i s t o g r a m % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% DefineImageHistogram() traverses the color cube tree and notes each colormap -% entry. A colormap entry is any node in the color cube tree where the -% of unique colors is not zero. -% -% The format of the DefineImageHistogram method is: -% -% DefineImageHistogram(const Image *image,NodeInfo *node_info, -% ColorPacket **unique_colors) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o node_info: the address of a structure of type NodeInfo which points to a -% node in the color cube tree that is to be pruned. -% -% o histogram: the image histogram. -% -*/ -static void DefineImageHistogram(const Image *image,NodeInfo *node_info, - ColorPacket **histogram) -{ - register long - i; - - unsigned long - number_children; - - /* - Traverse any children. - */ - number_children=image->matte == MagickFalse ? 8UL : 16UL; - for (i=0; i < (long) number_children; i++) - if (node_info->child[i] != (NodeInfo *) NULL) - DefineImageHistogram(image,node_info->child[i],histogram); - if (node_info->level == (MaxTreeDepth-1)) - { - register ColorPacket - *p; - - p=node_info->list; - for (i=0; i < (long) node_info->number_unique; i++) - { - (*histogram)->pixel=p->pixel; - (*histogram)->index=p->index; - (*histogram)->count=p->count; - (*histogram)++; - p++; - } - } -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % + D e s t r o y C o l o r L i s t % % % % % @@ -804,94 +510,6 @@ MagickExport void DestroyColorList(void) % % % % % % -+ D e s t r o y C u b e I n f o % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% DestroyCubeInfo() deallocates memory associated with a CubeInfo structure. -% -% The format of the DestroyCubeInfo method is: -% -% DestroyCubeInfo(const Image *image,CubeInfo *cube_info) -% -% A description of each parameter follows: -% -% o image: the image. -% -% o cube_info: the address of a structure of type CubeInfo. -% -*/ -static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info) -{ - register Nodes - *nodes; - - /* - Release color cube tree storage. - */ - DestroyColorCube(image,cube_info->root); - do - { - nodes=cube_info->node_queue->next; - cube_info->node_queue=(Nodes *) - RelinquishMagickMemory(cube_info->node_queue); - cube_info->node_queue=nodes; - } while (cube_info->node_queue != (Nodes *) NULL); - return((CubeInfo *) RelinquishMagickMemory(cube_info)); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -+ D e s t r o y C o l o r C u b e % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% DestroyColorCube() traverses the color cube tree and frees the list of -% unique colors. -% -% The format of the DestroyColorCube method is: -% -% void DestroyColorCube(const Image *image,const NodeInfo *node_info) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o node_info: the address of a structure of type NodeInfo which points to a -% node in the color cube tree that is to be pruned. -% -*/ -static void DestroyColorCube(const Image *image,NodeInfo *node_info) -{ - register long - i; - - unsigned long - number_children; - - /* - Traverse any children. - */ - number_children=image->matte == MagickFalse ? 8UL : 16UL; - for (i=0; i < (long) number_children; i++) - if (node_info->child[i] != (NodeInfo *) NULL) - DestroyColorCube(image,node_info->child[i]); - if (node_info->list != (ColorPacket *) NULL) - node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % + G e t C o l o r I n f o % % % % % @@ -1320,302 +938,14 @@ MagickExport void GetColorTuple(const MagickPixelPacket *pixel, (void) ConcatenateMagickString(tuple,",",MaxTextExtent); ConcatenateColorComponent(&color,IndexChannel,SVGCompliance,tuple); } - if (color.matte != MagickFalse) - { - (void) ConcatenateMagickString(tuple,",",MaxTextExtent); - ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple); - } - (void) ConcatenateMagickString(tuple,")",MaxTextExtent); - LocaleLower(tuple); - return; -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -+ G e t C u b e I n f o % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% GetCubeInfo() initializes the CubeInfo data structure. -% -% The format of the GetCubeInfo method is: -% -% cube_info=GetCubeInfo() -% -% A description of each parameter follows. -% -% o cube_info: A pointer to the Cube structure. -% -*/ -static CubeInfo *GetCubeInfo(void) -{ - CubeInfo - *cube_info; - - /* - Initialize tree to describe color cube. - */ - cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info)); - if (cube_info == (CubeInfo *) NULL) - return((CubeInfo *) NULL); - (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info)); - /* - Initialize root node. - */ - cube_info->root=GetNodeInfo(cube_info,0); - if (cube_info->root == (NodeInfo *) NULL) - return((CubeInfo *) NULL); - return(cube_info); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% G e t I m a g e H i s t o g r a m % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% GetImageHistogram() returns the unique colors in an image. -% -% The format of the GetImageHistogram method is: -% -% unsigned long GetImageHistogram(const Image *image, -% unsigned long *number_colors,ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o file: Write a histogram of the color distribution to this file handle. -% -% o exception: return any errors or warnings in this structure. -% -*/ -MagickExport ColorPacket *GetImageHistogram(const Image *image, - unsigned long *number_colors,ExceptionInfo *exception) -{ - ColorPacket - *histogram; - - CubeInfo - *cube_info; - - *number_colors=0; - histogram=(ColorPacket *) NULL; - cube_info=ClassifyImageColors(image,exception); - if (cube_info != (CubeInfo *) NULL) - { - histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors, - sizeof(*histogram)); - if (histogram == (ColorPacket *) NULL) - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); - else - { - ColorPacket - *root; - - *number_colors=cube_info->colors; - root=histogram; - DefineImageHistogram(image,cube_info->root,&root); - } - } - cube_info=DestroyCubeInfo(image,cube_info); - return(histogram); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -+ G e t N o d e I n f o % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% GetNodeInfo() allocates memory for a new node in the color cube tree and -% presets all fields to zero. -% -% The format of the GetNodeInfo method is: -% -% NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level) -% -% A description of each parameter follows. -% -% o cube_info: A pointer to the CubeInfo structure. -% -% o level: Specifies the level in the storage_class the node resides. -% -*/ -static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level) -{ - NodeInfo - *node_info; - - if (cube_info->free_nodes == 0) - { - Nodes - *nodes; - - /* - Allocate a new nodes of nodes. - */ - nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes)); - if (nodes == (Nodes *) NULL) - return((NodeInfo *) NULL); - nodes->next=cube_info->node_queue; - cube_info->node_queue=nodes; - cube_info->node_info=nodes->nodes; - cube_info->free_nodes=NodesInAList; - } - cube_info->free_nodes--; - node_info=cube_info->node_info++; - (void) ResetMagickMemory(node_info,0,sizeof(*node_info)); - node_info->level=level; - return(node_info); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% G e t N u m b e r C o l o r s % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% GetNumberColors() returns the number of unique colors in an image. -% -% The format of the GetNumberColors method is: -% -% unsigned long GetNumberColors(const Image *image,FILE *file, -% ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o file: Write a histogram of the color distribution to this file handle. -% -% o exception: return any errors or warnings in this structure. -% -*/ - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -static int HistogramCompare(const void *x,const void *y) -{ - const ColorPacket - *color_1, - *color_2; - - color_1=(const ColorPacket *) x; - color_2=(const ColorPacket *) y; - if (color_2->pixel.red != color_1->pixel.red) - return((int) color_1->pixel.red-(int) color_2->pixel.red); - if (color_2->pixel.green != color_1->pixel.green) - return((int) color_1->pixel.green-(int) color_2->pixel.green); - if (color_2->pixel.blue != color_1->pixel.blue) - return((int) color_1->pixel.blue-(int) color_2->pixel.blue); - return((int) color_2->count-(int) color_1->count); -} - -#if defined(__cplusplus) || defined(c_plusplus) -} -#endif - -MagickExport unsigned long GetNumberColors(const Image *image,FILE *file, - ExceptionInfo *exception) -{ -#define HistogramImageTag "Histogram/Image" - - char - color[MaxTextExtent], - hex[MaxTextExtent], - tuple[MaxTextExtent]; - - ColorPacket - *histogram; - - MagickPixelPacket - pixel; - - register ColorPacket - *p; - - register long - i; - - unsigned long - number_colors; - - number_colors=0; - if (file == (FILE *) NULL) + if (color.matte != MagickFalse) { - CubeInfo - *cube_info; - - cube_info=ClassifyImageColors(image,exception); - if (cube_info != (CubeInfo *) NULL) - number_colors=cube_info->colors; - cube_info=DestroyCubeInfo(image,cube_info); - return(number_colors); + (void) ConcatenateMagickString(tuple,",",MaxTextExtent); + ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple); } - histogram=GetImageHistogram(image,&number_colors,exception); - if (histogram == (ColorPacket *) NULL) - return(number_colors); - qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram), - HistogramCompare); - GetMagickPixelPacket(image,&pixel); - p=histogram; - for (i=0; i < (long) number_colors; i++) - { - SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel); - (void) CopyMagickString(tuple,"(",MaxTextExtent); - ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple); - (void) ConcatenateMagickString(tuple,",",MaxTextExtent); - ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple); - (void) ConcatenateMagickString(tuple,",",MaxTextExtent); - ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple); - if (pixel.colorspace == CMYKColorspace) - { - (void) ConcatenateMagickString(tuple,",",MaxTextExtent); - ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple); - } - if (pixel.matte != MagickFalse) - { - (void) ConcatenateMagickString(tuple,",",MaxTextExtent); - ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple); - } - (void) ConcatenateMagickString(tuple,")",MaxTextExtent); - (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception); - GetColorTuple(&pixel,MagickTrue,hex); - (void) fprintf(file,MagickSizeFormat,p->count); - (void) fprintf(file,": %s %s %s\n",tuple,hex,color); - if ((image->progress_monitor != (MagickProgressMonitor) NULL) && - (QuantumTick(i,number_colors) != MagickFalse)) - (void) image->progress_monitor(HistogramImageTag,i,number_colors, - image->client_data); - p++; - } - (void) fflush(file); - histogram=(ColorPacket *) RelinquishMagickMemory(histogram); - return(number_colors); + (void) ConcatenateMagickString(tuple,")",MaxTextExtent); + LocaleLower(tuple); + return; } /* @@ -1848,171 +1178,6 @@ MagickExport MagickBooleanType IsGrayImage(const Image *image, % % % % % % -% I s H i s t o g r a m I m a g e % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or -% less. -% -% The format of the IsHistogramImage method is: -% -% MagickBooleanType IsHistogramImage(const Image *image, -% ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o exception: return any errors or warnings in this structure. -% -*/ -MagickExport MagickBooleanType IsHistogramImage(const Image *image, - ExceptionInfo *exception) -{ -#define MaximumUniqueColors 1024 - - CubeInfo - *cube_info; - - long - y; - - MagickPixelPacket - pixel, - target; - - register const IndexPacket - *indexes; - - register const PixelPacket - *p; - - register long - x; - - register NodeInfo - *node_info; - - register long - i; - - unsigned long - id, - index, - level; - - CacheView - *image_view; - - assert(image != (Image *) NULL); - assert(image->signature == MagickSignature); - if (image->debug != MagickFalse) - (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); - if ((image->storage_class == PseudoClass) && (image->colors <= 256)) - return(MagickTrue); - if (image->storage_class == PseudoClass) - return(MagickFalse); - /* - Initialize color description tree. - */ - cube_info=GetCubeInfo(); - if (cube_info == (CubeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); - return(MagickFalse); - } - GetMagickPixelPacket(image,&pixel); - GetMagickPixelPacket(image,&target); - image_view=AcquireCacheView(image); - for (y=0; y < (long) image->rows; y++) - { - p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); - if (p == (const PixelPacket *) NULL) - break; - indexes=GetCacheViewVirtualIndexQueue(image_view); - for (x=0; x < (long) image->columns; x++) - { - /* - Start at the root and proceed level by level. - */ - node_info=cube_info->root; - index=MaxTreeDepth-1; - for (level=1; level < MaxTreeDepth; level++) - { - SetMagickPixelPacket(image,p,indexes+x,&pixel); - id=ColorToNodeId(image,&pixel,index); - if (node_info->child[id] == (NodeInfo *) NULL) - { - node_info->child[id]=GetNodeInfo(cube_info,level); - if (node_info->child[id] == (NodeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - break; - } - } - node_info=node_info->child[id]; - index--; - } - if (level < MaxTreeDepth) - break; - for (i=0; i < (long) node_info->number_unique; i++) - { - SetMagickPixelPacket(image,&node_info->list[i].pixel, - &node_info->list[i].index,&target); - if (IsMagickColorEqual(&pixel,&target) != MagickFalse) - break; - } - if (i < (long) node_info->number_unique) - node_info->list[i].count++; - else - { - /* - Add this unique color to the color list. - */ - if (node_info->number_unique == 0) - node_info->list=(ColorPacket *) AcquireMagickMemory( - sizeof(*node_info->list)); - else - node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, - (size_t) (i+1),sizeof(*node_info->list)); - if (node_info->list == (ColorPacket *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - break; - } - node_info->list[i].pixel=(*p); - if ((image->colorspace == CMYKColorspace) || - (image->storage_class == PseudoClass)) - node_info->list[i].index=indexes[x]; - node_info->list[i].count=1; - node_info->number_unique++; - cube_info->colors++; - if (cube_info->colors > MaximumUniqueColors) - break; - } - p++; - } - if (x < (long) image->columns) - break; - } - image_view=DestroyCacheView(image_view); - cube_info=DestroyCubeInfo(image,cube_info); - return(y < (long) image->rows ? MagickFalse : MagickTrue); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % + I s I m a g e S i m i l a r % % % % % @@ -2454,169 +1619,6 @@ MagickExport MagickBooleanType IsOpaqueImage(const Image *image, % % % % % % -% I s P a l e t t e I m a g e % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256 -% unique colors or less. -% -% The format of the IsPaletteImage method is: -% -% MagickBooleanType IsPaletteImage(const Image *image, -% ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o exception: return any errors or warnings in this structure. -% -*/ -MagickExport MagickBooleanType IsPaletteImage(const Image *image, - ExceptionInfo *exception) -{ - CubeInfo - *cube_info; - - long - y; - - MagickPixelPacket - pixel, - target; - - register const IndexPacket - *indexes; - - register const PixelPacket - *p; - - register long - x; - - register NodeInfo - *node_info; - - register long - i; - - unsigned long - id, - index, - level; - - CacheView - *image_view; - - assert(image != (Image *) NULL); - assert(image->signature == MagickSignature); - if (image->debug != MagickFalse) - (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); - if ((image->storage_class == PseudoClass) && (image->colors <= 256)) - return(MagickTrue); - if (image->storage_class == PseudoClass) - return(MagickFalse); - /* - Initialize color description tree. - */ - cube_info=GetCubeInfo(); - if (cube_info == (CubeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); - return(MagickFalse); - } - GetMagickPixelPacket(image,&pixel); - GetMagickPixelPacket(image,&target); - image_view=AcquireCacheView(image); - for (y=0; y < (long) image->rows; y++) - { - p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); - if (p == (const PixelPacket *) NULL) - break; - indexes=GetCacheViewVirtualIndexQueue(image_view); - for (x=0; x < (long) image->columns; x++) - { - /* - Start at the root and proceed level by level. - */ - node_info=cube_info->root; - index=MaxTreeDepth-1; - for (level=1; level < MaxTreeDepth; level++) - { - SetMagickPixelPacket(image,p,indexes+x,&pixel); - id=ColorToNodeId(image,&pixel,index); - if (node_info->child[id] == (NodeInfo *) NULL) - { - node_info->child[id]=GetNodeInfo(cube_info,level); - if (node_info->child[id] == (NodeInfo *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - break; - } - } - node_info=node_info->child[id]; - index--; - } - if (level < MaxTreeDepth) - break; - for (i=0; i < (long) node_info->number_unique; i++) - { - SetMagickPixelPacket(image,&node_info->list[i].pixel, - &node_info->list[i].index,&target); - if (IsMagickColorEqual(&pixel,&target) != MagickFalse) - break; - } - if (i < (long) node_info->number_unique) - node_info->list[i].count++; - else - { - /* - Add this unique color to the color list. - */ - if (node_info->number_unique == 0) - node_info->list=(ColorPacket *) AcquireMagickMemory( - sizeof(*node_info->list)); - else - node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, - (size_t) (i+1),sizeof(*node_info->list)); - if (node_info->list == (ColorPacket *) NULL) - { - (void) ThrowMagickException(exception,GetMagickModule(), - ResourceLimitError,"MemoryAllocationFailed","`%s'", - image->filename); - break; - } - node_info->list[i].pixel=(*p); - if ((image->colorspace == CMYKColorspace) || - (image->storage_class == PseudoClass)) - node_info->list[i].index=indexes[x]; - node_info->list[i].count=1; - node_info->number_unique++; - cube_info->colors++; - if (cube_info->colors > 256) - break; - } - p++; - } - if (x < (long) image->columns) - break; - } - image_view=DestroyCacheView(image_view); - cube_info=DestroyCubeInfo(image,cube_info); - return(y < (long) image->rows ? MagickFalse : MagickTrue); -} - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % % L i s t C o l o r I n f o % % % % % @@ -3429,118 +2431,3 @@ MagickExport MagickBooleanType QueryMagickColorname(const Image *image, } return(MagickTrue); } - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% U n i q u e I m a g e C o l o r s % -% % -% % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% UniqueImageColors() returns the unique colors of an image. -% -% The format of the UniqueImageColors method is: -% -% Image *UniqueImageColors(const Image *image,ExceptionInfo *exception) -% -% A description of each parameter follows. -% -% o image: the image. -% -% o exception: return any errors or warnings in this structure. -% -*/ - -static void UniqueColorsToImage(Image *image,CubeInfo *cube_info, - const NodeInfo *node_info,ExceptionInfo *exception) -{ -#define UniqueColorsImageTag "UniqueColors/Image" - - register long - i; - - unsigned long - number_children; - - /* - Traverse any children. - */ - number_children=image->matte == MagickFalse ? 8UL : 16UL; - for (i=0; i < (long) number_children; i++) - if (node_info->child[i] != (NodeInfo *) NULL) - UniqueColorsToImage(image,cube_info,node_info->child[i],exception); - if (node_info->level == (MaxTreeDepth-1)) - { - register ColorPacket - *p; - - register IndexPacket - *__restrict indexes; - - register PixelPacket - *__restrict q; - - p=node_info->list; - for (i=0; i < (long) node_info->number_unique; i++) - { - q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception); - if (q == (PixelPacket *) NULL) - continue; - indexes=GetAuthenticIndexQueue(image); - *q=p->pixel; - if (image->colorspace == CMYKColorspace) - *indexes=p->index; - if (SyncAuthenticPixels(image,exception) == MagickFalse) - break; - cube_info->x++; - p++; - } - if ((image->progress_monitor != (MagickProgressMonitor) NULL) && - (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse)) - (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress, - cube_info->colors,image->client_data); - cube_info->progress++; - } -} - -MagickExport Image *UniqueImageColors(const Image *image, - ExceptionInfo *exception) -{ - CubeInfo - *cube_info; - - Image - *unique_image; - - cube_info=ClassifyImageColors(image,exception); - if (cube_info == (CubeInfo *) NULL) - return((Image *) NULL); - unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception); - if (unique_image == (Image *) NULL) - return(unique_image); - if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse) - { - InheritException(exception,&unique_image->exception); - unique_image=DestroyImage(unique_image); - return((Image *) NULL); - } - UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception); - if (cube_info->colors < MaxColormapSize) - { - QuantizeInfo - *quantize_info; - - quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL); - quantize_info->number_colors=MaxColormapSize; - quantize_info->dither=MagickFalse; - quantize_info->tree_depth=8; - (void) QuantizeImage(quantize_info,unique_image); - quantize_info=DestroyQuantizeInfo(quantize_info); - } - cube_info=DestroyCubeInfo(image,cube_info); - return(unique_image); -} diff --git a/magick/color.h b/magick/color.h index eaed1745b..5ea63bafc 100644 --- a/magick/color.h +++ b/magick/color.h @@ -58,18 +58,6 @@ typedef struct _ColorInfo signature; } ColorInfo; -typedef struct _ColorPacket -{ - PixelPacket - pixel; - - IndexPacket - index; - - MagickSizeType - count; -} ColorPacket; - typedef struct _ErrorInfo { double @@ -85,22 +73,14 @@ extern MagickExport const ColorInfo *GetColorInfo(const char *,ExceptionInfo *), **GetColorInfoList(const char *,unsigned long *,ExceptionInfo *); -extern MagickExport ColorPacket - *GetImageHistogram(const Image *,unsigned long *,ExceptionInfo *); - -extern MagickExport Image - *UniqueImageColors(const Image *,ExceptionInfo *); - extern MagickExport MagickBooleanType IsColorSimilar(const Image *,const PixelPacket *,const PixelPacket *), IsGrayImage(const Image *,ExceptionInfo *), - IsHistogramImage(const Image *,ExceptionInfo *), IsImageSimilar(const Image *,const Image *,long *x,long *y,ExceptionInfo *), IsMagickColorSimilar(const MagickPixelPacket *,const MagickPixelPacket *), IsMonochromeImage(const Image *,ExceptionInfo *), IsOpacitySimilar(const Image *,const PixelPacket *,const PixelPacket *), IsOpaqueImage(const Image *,ExceptionInfo *), - IsPaletteImage(const Image *,ExceptionInfo *), ListColorInfo(FILE *,ExceptionInfo *), QueryColorDatabase(const char *,PixelPacket *,ExceptionInfo *), QueryColorname(const Image *,const PixelPacket *,const ComplianceType,char *, @@ -109,9 +89,6 @@ extern MagickExport MagickBooleanType QueryMagickColorname(const Image *,const MagickPixelPacket *, const ComplianceType,char *,ExceptionInfo *); -extern MagickExport unsigned long - GetNumberColors(const Image *,FILE *,ExceptionInfo *); - extern MagickExport void ConcatenateColorComponent(const MagickPixelPacket *,const ChannelType, const ComplianceType,char *), diff --git a/magick/histogram.c b/magick/histogram.c index 408ce2ecd..54bde2b68 100644 --- a/magick/histogram.c +++ b/magick/histogram.c @@ -42,6 +42,7 @@ */ #include "magick/studio.h" #include "magick/cache-view.h" +#include "magick/color-private.h" #include "magick/enhance.h" #include "magick/exception.h" #include "magick/exception-private.h" @@ -50,13 +51,889 @@ #include "magick/image.h" #include "magick/list.h" #include "magick/memory_.h" +#include "magick/monitor-private.h" +#include "magick/pixel-private.h" #include "magick/prepress.h" +#include "magick/quantize.h" #include "magick/registry.h" #include "magick/semaphore.h" #include "magick/splay-tree.h" #include "magick/statistic.h" #include "magick/string_.h" +/* + Define declarations. +*/ +#define MaxTreeDepth 8 +#define NodesInAList 1536 + +/* + Typedef declarations. +*/ +typedef struct _NodeInfo +{ + struct _NodeInfo + *child[16]; + + ColorPacket + *list; + + MagickSizeType + number_unique; + + unsigned long + level; +} NodeInfo; + +typedef struct _Nodes +{ + NodeInfo + nodes[NodesInAList]; + + struct _Nodes + *next; +} Nodes; + +typedef struct _CubeInfo +{ + NodeInfo + *root; + + long + x, + progress; + + unsigned long + colors, + free_nodes; + + NodeInfo + *node_info; + + Nodes + *node_queue; +} CubeInfo; + +/* + Forward declarations. +*/ +static CubeInfo + *GetCubeInfo(void); + +static NodeInfo + *GetNodeInfo(CubeInfo *,const unsigned long); + +static void + DestroyColorCube(const Image *,NodeInfo *); + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ C l a s s i f y I m a g e C o l o r s % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ClassifyImageColors() builds a populated CubeInfo tree for the specified +% image. The returned tree should be deallocated using DestroyCubeInfo() +% once it is no longer needed. +% +% The format of the ClassifyImageColors() method is: +% +% CubeInfo *ClassifyImageColors(const Image *image, +% ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o exception: return any errors or warnings in this structure. +% +*/ + +static inline unsigned long ColorToNodeId(const Image *image, + const MagickPixelPacket *pixel,unsigned long index) +{ + unsigned long + id; + + id=(unsigned long) ( + ((ScaleQuantumToChar(RoundToQuantum(pixel->red)) >> index) & 0x01) | + ((ScaleQuantumToChar(RoundToQuantum(pixel->green)) >> index) & 0x01) << 1 | + ((ScaleQuantumToChar(RoundToQuantum(pixel->blue)) >> index) & 0x01) << 2); + if (image->matte != MagickFalse) + id|=((ScaleQuantumToChar(RoundToQuantum(pixel->opacity)) >> index) & + 0x01) << 3; + return(id); +} + +static CubeInfo *ClassifyImageColors(const Image *image, + ExceptionInfo *exception) +{ +#define EvaluateImageTag " Compute image colors... " + + CubeInfo + *cube_info; + + long + y; + + MagickBooleanType + proceed; + + MagickPixelPacket + pixel, + target; + + NodeInfo + *node_info; + + register const IndexPacket + *indexes; + + register const PixelPacket + *p; + + register long + i, + x; + + register unsigned long + id, + index, + level; + + CacheView + *image_view; + + /* + Initialize color description tree. + */ + assert(image != (const Image *) NULL); + assert(image->signature == MagickSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + cube_info=GetCubeInfo(); + if (cube_info == (CubeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); + return(cube_info); + } + GetMagickPixelPacket(image,&pixel); + GetMagickPixelPacket(image,&target); + image_view=AcquireCacheView(image); + for (y=0; y < (long) image->rows; y++) + { + p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); + if (p == (const PixelPacket *) NULL) + break; + indexes=GetCacheViewVirtualIndexQueue(image_view); + for (x=0; x < (long) image->columns; x++) + { + /* + Start at the root and proceed level by level. + */ + node_info=cube_info->root; + index=MaxTreeDepth-1; + for (level=1; level < MaxTreeDepth; level++) + { + SetMagickPixelPacket(image,p,indexes+x,&pixel); + id=ColorToNodeId(image,&pixel,index); + if (node_info->child[id] == (NodeInfo *) NULL) + { + node_info->child[id]=GetNodeInfo(cube_info,level); + if (node_info->child[id] == (NodeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + return(0); + } + } + node_info=node_info->child[id]; + index--; + } + for (i=0; i < (long) node_info->number_unique; i++) + { + SetMagickPixelPacket(image,&node_info->list[i].pixel, + &node_info->list[i].index,&target); + if (IsMagickColorEqual(&pixel,&target) != MagickFalse) + break; + } + if (i < (long) node_info->number_unique) + node_info->list[i].count++; + else + { + if (node_info->number_unique == 0) + node_info->list=(ColorPacket *) AcquireMagickMemory( + sizeof(*node_info->list)); + else + node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, + (size_t) (i+1),sizeof(*node_info->list)); + if (node_info->list == (ColorPacket *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + return(0); + } + node_info->list[i].pixel=(*p); + if ((image->colorspace == CMYKColorspace) || + (image->storage_class == PseudoClass)) + node_info->list[i].index=indexes[x]; + node_info->list[i].count=1; + node_info->number_unique++; + cube_info->colors++; + } + p++; + } + proceed=SetImageProgress(image,EvaluateImageTag,y,image->rows); + if (proceed == MagickFalse) + break; + } + image_view=DestroyCacheView(image_view); + return(cube_info); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ D e f i n e I m a g e H i s t o g r a m % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DefineImageHistogram() traverses the color cube tree and notes each colormap +% entry. A colormap entry is any node in the color cube tree where the +% of unique colors is not zero. +% +% The format of the DefineImageHistogram method is: +% +% DefineImageHistogram(const Image *image,NodeInfo *node_info, +% ColorPacket **unique_colors) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o node_info: the address of a structure of type NodeInfo which points to a +% node in the color cube tree that is to be pruned. +% +% o histogram: the image histogram. +% +*/ +static void DefineImageHistogram(const Image *image,NodeInfo *node_info, + ColorPacket **histogram) +{ + register long + i; + + unsigned long + number_children; + + /* + Traverse any children. + */ + number_children=image->matte == MagickFalse ? 8UL : 16UL; + for (i=0; i < (long) number_children; i++) + if (node_info->child[i] != (NodeInfo *) NULL) + DefineImageHistogram(image,node_info->child[i],histogram); + if (node_info->level == (MaxTreeDepth-1)) + { + register ColorPacket + *p; + + p=node_info->list; + for (i=0; i < (long) node_info->number_unique; i++) + { + (*histogram)->pixel=p->pixel; + (*histogram)->index=p->index; + (*histogram)->count=p->count; + (*histogram)++; + p++; + } + } +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ D e s t r o y C u b e I n f o % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DestroyCubeInfo() deallocates memory associated with a CubeInfo structure. +% +% The format of the DestroyCubeInfo method is: +% +% DestroyCubeInfo(const Image *image,CubeInfo *cube_info) +% +% A description of each parameter follows: +% +% o image: the image. +% +% o cube_info: the address of a structure of type CubeInfo. +% +*/ +static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info) +{ + register Nodes + *nodes; + + /* + Release color cube tree storage. + */ + DestroyColorCube(image,cube_info->root); + do + { + nodes=cube_info->node_queue->next; + cube_info->node_queue=(Nodes *) + RelinquishMagickMemory(cube_info->node_queue); + cube_info->node_queue=nodes; + } while (cube_info->node_queue != (Nodes *) NULL); + return((CubeInfo *) RelinquishMagickMemory(cube_info)); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ D e s t r o y C o l o r C u b e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DestroyColorCube() traverses the color cube tree and frees the list of +% unique colors. +% +% The format of the DestroyColorCube method is: +% +% void DestroyColorCube(const Image *image,const NodeInfo *node_info) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o node_info: the address of a structure of type NodeInfo which points to a +% node in the color cube tree that is to be pruned. +% +*/ +static void DestroyColorCube(const Image *image,NodeInfo *node_info) +{ + register long + i; + + unsigned long + number_children; + + /* + Traverse any children. + */ + number_children=image->matte == MagickFalse ? 8UL : 16UL; + for (i=0; i < (long) number_children; i++) + if (node_info->child[i] != (NodeInfo *) NULL) + DestroyColorCube(image,node_info->child[i]); + if (node_info->list != (ColorPacket *) NULL) + node_info->list=(ColorPacket *) RelinquishMagickMemory(node_info->list); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ G e t C u b e I n f o % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GetCubeInfo() initializes the CubeInfo data structure. +% +% The format of the GetCubeInfo method is: +% +% cube_info=GetCubeInfo() +% +% A description of each parameter follows. +% +% o cube_info: A pointer to the Cube structure. +% +*/ +static CubeInfo *GetCubeInfo(void) +{ + CubeInfo + *cube_info; + + /* + Initialize tree to describe color cube. + */ + cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info)); + if (cube_info == (CubeInfo *) NULL) + return((CubeInfo *) NULL); + (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info)); + /* + Initialize root node. + */ + cube_info->root=GetNodeInfo(cube_info,0); + if (cube_info->root == (NodeInfo *) NULL) + return((CubeInfo *) NULL); + return(cube_info); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% G e t I m a g e H i s t o g r a m % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GetImageHistogram() returns the unique colors in an image. +% +% The format of the GetImageHistogram method is: +% +% unsigned long GetImageHistogram(const Image *image, +% unsigned long *number_colors,ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o file: Write a histogram of the color distribution to this file handle. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport ColorPacket *GetImageHistogram(const Image *image, + unsigned long *number_colors,ExceptionInfo *exception) +{ + ColorPacket + *histogram; + + CubeInfo + *cube_info; + + *number_colors=0; + histogram=(ColorPacket *) NULL; + cube_info=ClassifyImageColors(image,exception); + if (cube_info != (CubeInfo *) NULL) + { + histogram=(ColorPacket *) AcquireQuantumMemory((size_t) cube_info->colors, + sizeof(*histogram)); + if (histogram == (ColorPacket *) NULL) + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); + else + { + ColorPacket + *root; + + *number_colors=cube_info->colors; + root=histogram; + DefineImageHistogram(image,cube_info->root,&root); + } + } + cube_info=DestroyCubeInfo(image,cube_info); + return(histogram); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ G e t N o d e I n f o % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GetNodeInfo() allocates memory for a new node in the color cube tree and +% presets all fields to zero. +% +% The format of the GetNodeInfo method is: +% +% NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level) +% +% A description of each parameter follows. +% +% o cube_info: A pointer to the CubeInfo structure. +% +% o level: Specifies the level in the storage_class the node resides. +% +*/ +static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const unsigned long level) +{ + NodeInfo + *node_info; + + if (cube_info->free_nodes == 0) + { + Nodes + *nodes; + + /* + Allocate a new nodes of nodes. + */ + nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes)); + if (nodes == (Nodes *) NULL) + return((NodeInfo *) NULL); + nodes->next=cube_info->node_queue; + cube_info->node_queue=nodes; + cube_info->node_info=nodes->nodes; + cube_info->free_nodes=NodesInAList; + } + cube_info->free_nodes--; + node_info=cube_info->node_info++; + (void) ResetMagickMemory(node_info,0,sizeof(*node_info)); + node_info->level=level; + return(node_info); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% I s H i s t o g r a m I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or +% less. +% +% The format of the IsHistogramImage method is: +% +% MagickBooleanType IsHistogramImage(const Image *image, +% ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport MagickBooleanType IsHistogramImage(const Image *image, + ExceptionInfo *exception) +{ +#define MaximumUniqueColors 1024 + + CubeInfo + *cube_info; + + long + y; + + MagickPixelPacket + pixel, + target; + + register const IndexPacket + *indexes; + + register const PixelPacket + *p; + + register long + x; + + register NodeInfo + *node_info; + + register long + i; + + unsigned long + id, + index, + level; + + CacheView + *image_view; + + assert(image != (Image *) NULL); + assert(image->signature == MagickSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + if ((image->storage_class == PseudoClass) && (image->colors <= 256)) + return(MagickTrue); + if (image->storage_class == PseudoClass) + return(MagickFalse); + /* + Initialize color description tree. + */ + cube_info=GetCubeInfo(); + if (cube_info == (CubeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); + return(MagickFalse); + } + GetMagickPixelPacket(image,&pixel); + GetMagickPixelPacket(image,&target); + image_view=AcquireCacheView(image); + for (y=0; y < (long) image->rows; y++) + { + p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); + if (p == (const PixelPacket *) NULL) + break; + indexes=GetCacheViewVirtualIndexQueue(image_view); + for (x=0; x < (long) image->columns; x++) + { + /* + Start at the root and proceed level by level. + */ + node_info=cube_info->root; + index=MaxTreeDepth-1; + for (level=1; level < MaxTreeDepth; level++) + { + SetMagickPixelPacket(image,p,indexes+x,&pixel); + id=ColorToNodeId(image,&pixel,index); + if (node_info->child[id] == (NodeInfo *) NULL) + { + node_info->child[id]=GetNodeInfo(cube_info,level); + if (node_info->child[id] == (NodeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + break; + } + } + node_info=node_info->child[id]; + index--; + } + if (level < MaxTreeDepth) + break; + for (i=0; i < (long) node_info->number_unique; i++) + { + SetMagickPixelPacket(image,&node_info->list[i].pixel, + &node_info->list[i].index,&target); + if (IsMagickColorEqual(&pixel,&target) != MagickFalse) + break; + } + if (i < (long) node_info->number_unique) + node_info->list[i].count++; + else + { + /* + Add this unique color to the color list. + */ + if (node_info->number_unique == 0) + node_info->list=(ColorPacket *) AcquireMagickMemory( + sizeof(*node_info->list)); + else + node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, + (size_t) (i+1),sizeof(*node_info->list)); + if (node_info->list == (ColorPacket *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + break; + } + node_info->list[i].pixel=(*p); + if ((image->colorspace == CMYKColorspace) || + (image->storage_class == PseudoClass)) + node_info->list[i].index=indexes[x]; + node_info->list[i].count=1; + node_info->number_unique++; + cube_info->colors++; + if (cube_info->colors > MaximumUniqueColors) + break; + } + p++; + } + if (x < (long) image->columns) + break; + } + image_view=DestroyCacheView(image_view); + cube_info=DestroyCubeInfo(image,cube_info); + return(y < (long) image->rows ? MagickFalse : MagickTrue); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% I s P a l e t t e I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256 +% unique colors or less. +% +% The format of the IsPaletteImage method is: +% +% MagickBooleanType IsPaletteImage(const Image *image, +% ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport MagickBooleanType IsPaletteImage(const Image *image, + ExceptionInfo *exception) +{ + CubeInfo + *cube_info; + + long + y; + + MagickPixelPacket + pixel, + target; + + register const IndexPacket + *indexes; + + register const PixelPacket + *p; + + register long + x; + + register NodeInfo + *node_info; + + register long + i; + + unsigned long + id, + index, + level; + + CacheView + *image_view; + + assert(image != (Image *) NULL); + assert(image->signature == MagickSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + if ((image->storage_class == PseudoClass) && (image->colors <= 256)) + return(MagickTrue); + if (image->storage_class == PseudoClass) + return(MagickFalse); + /* + Initialize color description tree. + */ + cube_info=GetCubeInfo(); + if (cube_info == (CubeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); + return(MagickFalse); + } + GetMagickPixelPacket(image,&pixel); + GetMagickPixelPacket(image,&target); + image_view=AcquireCacheView(image); + for (y=0; y < (long) image->rows; y++) + { + p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); + if (p == (const PixelPacket *) NULL) + break; + indexes=GetCacheViewVirtualIndexQueue(image_view); + for (x=0; x < (long) image->columns; x++) + { + /* + Start at the root and proceed level by level. + */ + node_info=cube_info->root; + index=MaxTreeDepth-1; + for (level=1; level < MaxTreeDepth; level++) + { + SetMagickPixelPacket(image,p,indexes+x,&pixel); + id=ColorToNodeId(image,&pixel,index); + if (node_info->child[id] == (NodeInfo *) NULL) + { + node_info->child[id]=GetNodeInfo(cube_info,level); + if (node_info->child[id] == (NodeInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + break; + } + } + node_info=node_info->child[id]; + index--; + } + if (level < MaxTreeDepth) + break; + for (i=0; i < (long) node_info->number_unique; i++) + { + SetMagickPixelPacket(image,&node_info->list[i].pixel, + &node_info->list[i].index,&target); + if (IsMagickColorEqual(&pixel,&target) != MagickFalse) + break; + } + if (i < (long) node_info->number_unique) + node_info->list[i].count++; + else + { + /* + Add this unique color to the color list. + */ + if (node_info->number_unique == 0) + node_info->list=(ColorPacket *) AcquireMagickMemory( + sizeof(*node_info->list)); + else + node_info->list=(ColorPacket *) ResizeQuantumMemory(node_info->list, + (size_t) (i+1),sizeof(*node_info->list)); + if (node_info->list == (ColorPacket *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + ResourceLimitError,"MemoryAllocationFailed","`%s'", + image->filename); + break; + } + node_info->list[i].pixel=(*p); + if ((image->colorspace == CMYKColorspace) || + (image->storage_class == PseudoClass)) + node_info->list[i].index=indexes[x]; + node_info->list[i].count=1; + node_info->number_unique++; + cube_info->colors++; + if (cube_info->colors > 256) + break; + } + p++; + } + if (x < (long) image->columns) + break; + } + image_view=DestroyCacheView(image_view); + cube_info=DestroyCubeInfo(image,cube_info); + return(y < (long) image->rows ? MagickFalse : MagickTrue); +} + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -102,10 +979,8 @@ % from the minimum and maximum points by this color value. % */ - MagickExport MagickBooleanType MinMaxStretchImage(Image *image, - const ChannelType channel, const double black_value, - const double white_value) + const ChannelType channel,const double black_value,const double white_value) { double min,max; @@ -113,52 +988,307 @@ MagickExport MagickBooleanType MinMaxStretchImage(Image *image, MagickStatusType status; - if ((channel & SyncChannels) != 0 ) + if ((channel & SyncChannels) != 0) { /* - autolevel all channels equally + Auto-level all channels equally. */ - GetImageChannelRange(image, channel, &min, &max, &image->exception); - min += black_value; max -= white_value; - return LevelImageChannel(image, channel, min, max, 1.0); + (void) GetImageChannelRange(image,channel,&min,&max,&image->exception); + min+=black_value; + max-=white_value; + return(LevelImageChannel(image,channel,min,max,1.0)); } - /* - autolevel each channel separateally + Auto-level each channel separately. */ - status = MagickTrue; + status=MagickTrue; if ((channel & RedChannel) != 0) { - GetImageChannelRange(image, RedChannel, &min, &max, &image->exception); - min += black_value; max -= white_value; - status = status && LevelImageChannel(image, RedChannel, min, max, 1.0); + (void) GetImageChannelRange(image,RedChannel,&min,&max,&image->exception); + min+=black_value; + max-=white_value; + status&=LevelImageChannel(image,RedChannel,min,max,1.0); } if ((channel & GreenChannel) != 0) { - GetImageChannelRange(image, GreenChannel, &min, &max, &image->exception); - min += black_value; max -= white_value; - status = status && LevelImageChannel(image, GreenChannel, min, max, 1.0); + (void) GetImageChannelRange(image,GreenChannel,&min,&max, + &image->exception); + min+=black_value; + max-=white_value; + status&=LevelImageChannel(image,GreenChannel,min,max,1.0); } if ((channel & BlueChannel) != 0) { - GetImageChannelRange(image, BlueChannel, &min, &max, &image->exception); - min += black_value; max -= white_value; - status = status && LevelImageChannel(image, BlueChannel, min, max, 1.0); + (void) GetImageChannelRange(image,BlueChannel,&min,&max, + &image->exception); + min+=black_value; + max-=white_value; + status&=LevelImageChannel(image,BlueChannel,min,max,1.0); } if (((channel & OpacityChannel) != 0) && - (image->matte == MagickTrue)) + (image->matte == MagickTrue)) { - GetImageChannelRange(image, OpacityChannel, &min, &max, &image->exception); - min += black_value; max -= white_value; - status = status && LevelImageChannel(image, OpacityChannel, min, max, 1.0); + (void) GetImageChannelRange(image,OpacityChannel,&min,&max, + &image->exception); + min+=black_value; + max-=white_value; + status&=LevelImageChannel(image,OpacityChannel,min,max,1.0); } if (((channel & IndexChannel) != 0) && - (image->colorspace == CMYKColorspace)) + (image->colorspace == CMYKColorspace)) { - GetImageChannelRange(image, IndexChannel, &min, &max, &image->exception); - min += black_value; max -= white_value; - status = status && LevelImageChannel(image, IndexChannel, min, max, 1.0); + (void) GetImageChannelRange(image,IndexChannel,&min,&max, + &image->exception); + min+=black_value; + max-=white_value; + status&=LevelImageChannel(image,IndexChannel,min,max,1.0); } return(status != 0 ? MagickTrue : MagickFalse); } +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% G e t N u m b e r C o l o r s % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GetNumberColors() returns the number of unique colors in an image. +% +% The format of the GetNumberColors method is: +% +% unsigned long GetNumberColors(const Image *image,FILE *file, +% ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o file: Write a histogram of the color distribution to this file handle. +% +% o exception: return any errors or warnings in this structure. +% +*/ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static int HistogramCompare(const void *x,const void *y) +{ + const ColorPacket + *color_1, + *color_2; + + color_1=(const ColorPacket *) x; + color_2=(const ColorPacket *) y; + if (color_2->pixel.red != color_1->pixel.red) + return((int) color_1->pixel.red-(int) color_2->pixel.red); + if (color_2->pixel.green != color_1->pixel.green) + return((int) color_1->pixel.green-(int) color_2->pixel.green); + if (color_2->pixel.blue != color_1->pixel.blue) + return((int) color_1->pixel.blue-(int) color_2->pixel.blue); + return((int) color_2->count-(int) color_1->count); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +MagickExport unsigned long GetNumberColors(const Image *image,FILE *file, + ExceptionInfo *exception) +{ +#define HistogramImageTag "Histogram/Image" + + char + color[MaxTextExtent], + hex[MaxTextExtent], + tuple[MaxTextExtent]; + + ColorPacket + *histogram; + + MagickPixelPacket + pixel; + + register ColorPacket + *p; + + register long + i; + + unsigned long + number_colors; + + number_colors=0; + if (file == (FILE *) NULL) + { + CubeInfo + *cube_info; + + cube_info=ClassifyImageColors(image,exception); + if (cube_info != (CubeInfo *) NULL) + number_colors=cube_info->colors; + cube_info=DestroyCubeInfo(image,cube_info); + return(number_colors); + } + histogram=GetImageHistogram(image,&number_colors,exception); + if (histogram == (ColorPacket *) NULL) + return(number_colors); + qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram), + HistogramCompare); + GetMagickPixelPacket(image,&pixel); + p=histogram; + for (i=0; i < (long) number_colors; i++) + { + SetMagickPixelPacket(image,&p->pixel,&p->index,&pixel); + (void) CopyMagickString(tuple,"(",MaxTextExtent); + ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple); + (void) ConcatenateMagickString(tuple,",",MaxTextExtent); + ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple); + (void) ConcatenateMagickString(tuple,",",MaxTextExtent); + ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple); + if (pixel.colorspace == CMYKColorspace) + { + (void) ConcatenateMagickString(tuple,",",MaxTextExtent); + ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple); + } + if (pixel.matte != MagickFalse) + { + (void) ConcatenateMagickString(tuple,",",MaxTextExtent); + ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple); + } + (void) ConcatenateMagickString(tuple,")",MaxTextExtent); + (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception); + GetColorTuple(&pixel,MagickTrue,hex); + (void) fprintf(file,MagickSizeFormat,p->count); + (void) fprintf(file,": %s %s %s\n",tuple,hex,color); + if ((image->progress_monitor != (MagickProgressMonitor) NULL) && + (QuantumTick(i,number_colors) != MagickFalse)) + (void) image->progress_monitor(HistogramImageTag,i,number_colors, + image->client_data); + p++; + } + (void) fflush(file); + histogram=(ColorPacket *) RelinquishMagickMemory(histogram); + return(number_colors); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% U n i q u e I m a g e C o l o r s % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% UniqueImageColors() returns the unique colors of an image. +% +% The format of the UniqueImageColors method is: +% +% Image *UniqueImageColors(const Image *image,ExceptionInfo *exception) +% +% A description of each parameter follows. +% +% o image: the image. +% +% o exception: return any errors or warnings in this structure. +% +*/ + +static void UniqueColorsToImage(Image *image,CubeInfo *cube_info, + const NodeInfo *node_info,ExceptionInfo *exception) +{ +#define UniqueColorsImageTag "UniqueColors/Image" + + register long + i; + + unsigned long + number_children; + + /* + Traverse any children. + */ + number_children=image->matte == MagickFalse ? 8UL : 16UL; + for (i=0; i < (long) number_children; i++) + if (node_info->child[i] != (NodeInfo *) NULL) + UniqueColorsToImage(image,cube_info,node_info->child[i],exception); + if (node_info->level == (MaxTreeDepth-1)) + { + register ColorPacket + *p; + + register IndexPacket + *__restrict indexes; + + register PixelPacket + *__restrict q; + + p=node_info->list; + for (i=0; i < (long) node_info->number_unique; i++) + { + q=QueueAuthenticPixels(image,cube_info->x,0,1,1,exception); + if (q == (PixelPacket *) NULL) + continue; + indexes=GetAuthenticIndexQueue(image); + *q=p->pixel; + if (image->colorspace == CMYKColorspace) + *indexes=p->index; + if (SyncAuthenticPixels(image,exception) == MagickFalse) + break; + cube_info->x++; + p++; + } + if ((image->progress_monitor != (MagickProgressMonitor) NULL) && + (QuantumTick(cube_info->progress,cube_info->colors) != MagickFalse)) + (void) image->progress_monitor(UniqueColorsImageTag,cube_info->progress, + cube_info->colors,image->client_data); + cube_info->progress++; + } +} + +MagickExport Image *UniqueImageColors(const Image *image, + ExceptionInfo *exception) +{ + CubeInfo + *cube_info; + + Image + *unique_image; + + cube_info=ClassifyImageColors(image,exception); + if (cube_info == (CubeInfo *) NULL) + return((Image *) NULL); + unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception); + if (unique_image == (Image *) NULL) + return(unique_image); + if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse) + { + InheritException(exception,&unique_image->exception); + unique_image=DestroyImage(unique_image); + return((Image *) NULL); + } + UniqueColorsToImage(unique_image,cube_info,cube_info->root,exception); + if (cube_info->colors < MaxColormapSize) + { + QuantizeInfo + *quantize_info; + + quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL); + quantize_info->number_colors=MaxColormapSize; + quantize_info->dither=MagickFalse; + quantize_info->tree_depth=8; + (void) QuantizeImage(quantize_info,unique_image); + quantize_info=DestroyQuantizeInfo(quantize_info); + } + cube_info=DestroyCubeInfo(image,cube_info); + return(unique_image); +} diff --git a/magick/histogram.h b/magick/histogram.h index cbf6ff837..3397998d4 100644 --- a/magick/histogram.h +++ b/magick/histogram.h @@ -22,9 +22,32 @@ extern "C" { #endif +typedef struct _ColorPacket +{ + PixelPacket + pixel; + + IndexPacket + index; + + MagickSizeType + count; +} ColorPacket; + +extern MagickExport ColorPacket + *GetImageHistogram(const Image *,unsigned long *,ExceptionInfo *); + +extern MagickExport Image + *UniqueImageColors(const Image *,ExceptionInfo *); + extern MagickExport MagickBooleanType + IsHistogramImage(const Image *,ExceptionInfo *), + IsPaletteImage(const Image *,ExceptionInfo *), MinMaxStretchImage(Image *,const ChannelType,const double,const double); +extern MagickExport unsigned long + GetNumberColors(const Image *,FILE *,ExceptionInfo *); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/magick/identify.c b/magick/identify.c index 76766a91e..6554a5965 100644 --- a/magick/identify.c +++ b/magick/identify.c @@ -60,6 +60,7 @@ #include "magick/exception-private.h" #include "magick/gem.h" #include "magick/geometry.h" +#include "magick/histogram.h" #include "magick/identify.h" #include "magick/image.h" #include "magick/image-private.h" diff --git a/magick/image.c b/magick/image.c index 24230f199..e53aa53c5 100644 --- a/magick/image.c +++ b/magick/image.c @@ -66,8 +66,9 @@ #include "magick/exception-private.h" #include "magick/gem.h" #include "magick/geometry.h" -#include "magick/list.h" +#include "magick/histogram.h" #include "magick/image-private.h" +#include "magick/list.h" #include "magick/magic.h" #include "magick/magick.h" #include "magick/memory_.h" diff --git a/magick/magick.c b/magick/magick.c index 0d52e8701..3b03176f0 100644 --- a/magick/magick.c +++ b/magick/magick.c @@ -805,6 +805,7 @@ static void *DestroyMagickNode(void *magick_info) static MagickBooleanType InitializeMagickList(ExceptionInfo *exception) { + (void) exception; if ((magick_list == (SplayTreeInfo *) NULL) && (instantiate_magick == MagickFalse)) { diff --git a/magick/property.c b/magick/property.c index 155b4aebf..abd9024b9 100644 --- a/magick/property.c +++ b/magick/property.c @@ -53,6 +53,8 @@ #include "magick/fx-private.h" #include "magick/gem.h" #include "magick/geometry.h" +#include "magick/histogram.h" +#include "magick/image.h" #include "magick/image.h" #include "magick/layer.h" #include "magick/list.h" diff --git a/magick/quantize.c b/magick/quantize.c index 1fb3c3cd4..7dc2131b1 100644 --- a/magick/quantize.c +++ b/magick/quantize.c @@ -182,6 +182,7 @@ #include "magick/enhance.h" #include "magick/exception.h" #include "magick/exception-private.h" +#include "magick/histogram.h" #include "magick/image.h" #include "magick/image-private.h" #include "magick/list.h" diff --git a/magick/version.h b/magick/version.h index 9dd6addbc..343c1a587 100644 --- a/magick/version.h +++ b/magick/version.h @@ -31,8 +31,8 @@ extern "C" { #define MagickLibVersionText "6.5.7" #define MagickLibVersionNumber 2,0,0 #define MagickLibSubversion "-0" -#define MagickReleaseDate "2009-10-12" -#define MagickChangeDate "20091010" +#define MagickReleaseDate "2009-10-13" +#define MagickChangeDate "20091014" #define MagickAuthoritativeURL "http://www.imagemagick.org" #define MagickHomeURL "file:///usr/local/share/doc/ImageMagick-6.5.7/index.html" #if (MAGICKCORE_QUANTUM_DEPTH == 8) -- 2.40.0