diff --git a/magick/cache.c b/magick/cache.c
index 48e2ce8..89fdcad 100644
--- a/magick/cache.c
+++ b/magick/cache.c
@@ -2132,7 +2132,7 @@
}
(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 65e3ee5..8c054b8 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.
@@ -337,53 +335,6 @@
"</colormap>";
/*
- 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.
*/
static LinkedListInfo
@@ -398,191 +349,9 @@
/*
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 @@
% %
% %
% %
-+ 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 @@
% %
% %
% %
-+ 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 %
% %
% %
@@ -1335,294 +953,6 @@
% %
% %
% %
-+ 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)
- {
- 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);
-}
-
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
+ I n i t i a l i z e C o l o r L i s t %
% %
% %
@@ -1848,171 +1178,6 @@
% %
% %
% %
-% 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 @@
% %
% %
% %
-% 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 @@
}
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 eaed174..5ea63ba 100644
--- a/magick/color.h
+++ b/magick/color.h
@@ -58,18 +58,6 @@
signature;
} ColorInfo;
-typedef struct _ColorPacket
-{
- PixelPacket
- pixel;
-
- IndexPacket
- index;
-
- MagickSizeType
- count;
-} ColorPacket;
-
typedef struct _ErrorInfo
{
double
@@ -85,22 +73,14 @@
*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 @@
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 408ce2e..54bde2b 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,7 +51,10 @@
#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"
@@ -58,6 +62,879 @@
#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 @@
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 cbf6ff8..3397998 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 76766a9..6554a59 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 24230f1..e53aa53 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 0d52e87..3b03176 100644
--- a/magick/magick.c
+++ b/magick/magick.c
@@ -805,6 +805,7 @@
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 155b4ae..abd9024 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 1fb3c3c..7dc2131 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 9dd6add..343c1a5 100644
--- a/magick/version.h
+++ b/magick/version.h
@@ -31,8 +31,8 @@
#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)