% %
% %
% %
-% H H IIIII SSSSS TTTTT OOO GGGG RRRR AAA M M %
-% H H I SS T O O G R R A A MM MM %
-% HHHHH I SSS T O O G GG RRRR AAAAA M M M %
-% H H I SS T O O G G R R A A M M %
-% H H IIIII SSSSS T OOO GGG R R A A M M %
+% H H IIIII SSSSS TTTTT OOO GGGG RRRR AAA M M %
+% H H I SS T O O G R R A A MM MM %
+% HHHHH I SSS T O O G GG RRRR AAAAA M M M %
+% H H I SS T O O G G R R A A M M %
+% H H IIIII SSSSS T OOO GGG R R A A M M %
% %
% %
-% MagickCore Histogram Methods %
+% Write A Histogram Image. %
% %
% Software Design %
-% Anthony Thyssen %
-% Fred Weinhaus %
-% August 2009 %
+% John Cristy %
+% July 1992 %
% %
% %
% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
Include declarations.
*/
#include "magick/studio.h"
-#include "magick/cache-view.h"
+#include "magick/property.h"
+#include "magick/blob.h"
+#include "magick/blob-private.h"
+#include "magick/cache.h"
+#include "magick/color.h"
#include "magick/color-private.h"
-#include "magick/enhance.h"
+#include "magick/constitute.h"
#include "magick/exception.h"
#include "magick/exception-private.h"
-#include "magick/hashmap.h"
+#include "magick/geometry.h"
#include "magick/histogram.h"
-#include "magick/image.h"
-#include "magick/list.h"
+#include "magick/image-private.h"
+#include "magick/magick.h"
#include "magick/memory_.h"
+#include "magick/monitor.h"
#include "magick/monitor-private.h"
#include "magick/option.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/resource_.h"
+#include "magick/quantum-private.h"
+#include "magick/static.h"
#include "magick/statistic.h"
#include "magick/string_.h"
-\f
-/*
- Define declarations.
-*/
-#define MaxTreeDepth 8
-#define NodesInAList 1536
-\f
-/*
- 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;
+#include "magick/module.h"
+#include "magick/utility.h"
\f
/*
Forward declarations.
*/
-static CubeInfo
- *GetCubeInfo(void);
-
-static NodeInfo
- *GetNodeInfo(CubeInfo *,const unsigned long);
-
-static void
- DestroyColorCube(const Image *,NodeInfo *);
+static MagickBooleanType
+ WriteHISTOGRAMImage(const ImageInfo *,Image *);
\f
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
-+ C l a s s i f y I m a g e C o l o r s %
+% R e g i s t e r H I S T O G R A M I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% ClassifyImageColors() builds a populated CubeInfo tree for the specified
-% image. The returned tree should be deallocated using DestroyCubeInfo()
-% once it is no longer needed.
+% RegisterHISTOGRAMImage() adds attributes for the Histogram image format
+% to the list of supported formats. The attributes include the image format
+% tag, a method to read and/or write the format, whether the format
+% supports the saving of more than one frame to the same file or blob,
+% whether the format supports native in-memory I/O, and a brief
+% description of the format.
%
-% The format of the ClassifyImageColors() method is:
+% The format of the RegisterHISTOGRAMImage 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.
+% size_t RegisterHISTOGRAMImage(void)
%
*/
-
-static inline unsigned long ColorToNodeId(const Image *image,
- const MagickPixelPacket *pixel,unsigned long index)
+ModuleExport size_t RegisterHISTOGRAMImage(void)
{
- unsigned long
- id;
-
- id=(unsigned long) (
- ((ScaleQuantumToChar(ClampToQuantum(pixel->red)) >> index) & 0x01) |
- ((ScaleQuantumToChar(ClampToQuantum(pixel->green)) >> index) & 0x01) << 1 |
- ((ScaleQuantumToChar(ClampToQuantum(pixel->blue)) >> index) & 0x01) << 2);
- if (image->matte != MagickFalse)
- id|=((ScaleQuantumToChar(ClampToQuantum(pixel->opacity)) >> index) &
- 0x01) << 3;
- return(id);
-}
-
-static CubeInfo *ClassifyImageColors(const Image *image,
- ExceptionInfo *exception)
-{
-#define EvaluateImageTag " Compute image colors... "
-
- CacheView
- *image_view;
-
- 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;
-
- /*
- 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);
+ MagickInfo
+ *entry;
+
+ entry=SetMagickInfo("HISTOGRAM");
+ entry->encoder=(EncodeImageHandler *) WriteHISTOGRAMImage;
+ entry->adjoin=MagickFalse;
+ entry->format_type=ImplicitFormatType;
+ entry->description=ConstantString("Histogram of the image");
+ entry->module=ConstantString("HISTOGRAM");
+ (void) RegisterMagickInfo(entry);
+ return(MagickImageCoderSignature);
}
\f
/*
% %
% %
% %
-+ D e f i n e I m a g e H i s t o g r a m %
+% U n r e g i s t e r H I S T O G R A M I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% 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.
+% UnregisterHISTOGRAMImage() removes format registrations made by the
+% HISTOGRAM module from the list of supported formats.
%
-% 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.
+% The format of the UnregisterHISTOGRAMImage method is:
%
-% o histogram: the image histogram.
+% UnregisterHISTOGRAMImage(void)
%
*/
-static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
- ColorPacket **histogram)
+ModuleExport void UnregisterHISTOGRAMImage(void)
{
- 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++;
- }
- }
+ (void) UnregisterMagickInfo("HISTOGRAM");
}
\f
/*
% %
% %
% %
-+ D e s t r o y C u b e I n f o %
+% W r i t e H I S T O G R A M I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
-%
-% The format of the DestroyCubeInfo method is:
-%
-% DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
+% WriteHISTOGRAMImage() writes an image to a file in Histogram format.
+% The image shows a histogram of the color (or gray) values in the image. The
+% image consists of three overlaid histograms: a red one for the red channel,
+% a green one for the green channel, and a blue one for the blue channel. The
+% image comment contains a list of unique pixel values and the number of times
+% each occurs in the image.
%
-% A description of each parameter follows:
+% This method is strongly based on a similar one written by
+% muquit@warm.semcor.com which in turn is based on ppmhistmap of netpbm.
%
-% o image: the image.
+% The format of the WriteHISTOGRAMImage method is:
%
-% 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));
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-+ 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)
+% MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info,
+% Image *image)
%
% A description of each parameter follows.
%
-% o image: the image.
+% o image_info: the image info.
%
-% 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 image: The image.
%
*/
-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);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-+ 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)
+static inline size_t MagickMax(const size_t x,const size_t y)
{
- CubeInfo
- *cube_info;
-
- /*
- Initialize tree to describe color cube.
- */
- cube_info=(CubeInfo *) AcquireAlignedMemory(1,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);
+ if (x > y)
+ return(x);
+ return(y);
}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% 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)
+
+static MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info,
+ Image *image)
{
- ColorPacket
- *histogram;
+#define HistogramDensity "256x100"
- CubeInfo
- *cube_info;
+ ChannelType
+ channel;
- *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);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-+ 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;
+ char
+ filename[MaxTextExtent];
- if (cube_info->free_nodes == 0)
- {
- Nodes
- *nodes;
+ const char
+ *option;
- /*
- Allocate a new nodes of nodes.
- */
- nodes=(Nodes *) AcquireAlignedMemory(1,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);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% 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
+ ExceptionInfo
+ *exception;
- CacheView
- *image_view;
+ Image
+ *histogram_image;
- CubeInfo
- *cube_info;
+ ImageInfo
+ *write_info;
- long
+ ssize_t
y;
+ MagickBooleanType
+ status;
+
MagickPixelPacket
- pixel,
- target;
+ *histogram;
+
+ MagickRealType
+ maximum,
+ scale;
- register const IndexPacket
- *indexes;
+ RectangleInfo
+ geometry;
register const PixelPacket
*p;
- register long
+ register ssize_t
x;
- register NodeInfo
- *node_info;
-
- register long
- i;
+ register PixelPacket
+ *q,
+ *r;
- unsigned long
- id,
- index,
- level;
+ size_t
+ length;
+ /*
+ Allocate histogram image.
+ */
+ assert(image_info != (const ImageInfo *) NULL);
+ assert(image_info->signature == MagickSignature);
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);
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+ image_info->filename);
+ SetGeometry(image,&geometry);
+ if (image_info->density == (char *) NULL)
+ (void) ParseAbsoluteGeometry(HistogramDensity,&geometry);
+ else
+ (void) ParseAbsoluteGeometry(image_info->density,&geometry);
+ histogram_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
+ &image->exception);
+ if (histogram_image == (Image *) NULL)
+ ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+ (void) SetImageStorageClass(histogram_image,DirectClass);
/*
- Initialize color description tree.
+ Allocate histogram count arrays.
*/
- cube_info=GetCubeInfo();
- if (cube_info == (CubeInfo *) NULL)
+ length=MagickMax((size_t) ScaleQuantumToChar((Quantum) QuantumRange)+1UL,
+ histogram_image->columns);
+ histogram=(MagickPixelPacket *) AcquireQuantumMemory(length,
+ sizeof(*histogram));
+ if (histogram == (MagickPixelPacket *) NULL)
{
- (void) ThrowMagickException(exception,GetMagickModule(),
- ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
- return(MagickFalse);
+ histogram_image=DestroyImage(histogram_image);
+ ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
}
- GetMagickPixelPacket(image,&pixel);
- GetMagickPixelPacket(image,&target);
- image_view=AcquireCacheView(image);
- for (y=0; y < (long) image->rows; y++)
+ /*
+ Initialize histogram count arrays.
+ */
+ channel=image_info->channel;
+ (void) ResetMagickMemory(histogram,0,length*sizeof(*histogram));
+ for (y=0; y < (ssize_t) image->rows; y++)
{
- p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+ p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
if (p == (const PixelPacket *) NULL)
break;
- indexes=GetCacheViewVirtualIndexQueue(image_view);
- for (x=0; x < (long) image->columns; x++)
+ for (x=0; x < (ssize_t) 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;
- }
+ if ((channel & RedChannel) != 0)
+ histogram[ScaleQuantumToChar(GetRedPixelComponent(p))].red++;
+ if ((channel & GreenChannel) != 0)
+ histogram[ScaleQuantumToChar(GetGreenPixelComponent(p))].green++;
+ if ((channel & BlueChannel) != 0)
+ histogram[ScaleQuantumToChar(GetBluePixelComponent(p))].blue++;
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);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% 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)
-{
- CacheView
- *image_view;
-
- 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;
-
- 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);
+ maximum=histogram[0].red;
+ for (x=0; x < (ssize_t) histogram_image->columns; x++)
+ {
+ if (((channel & RedChannel) != 0) && (maximum < histogram[x].red))
+ maximum=histogram[x].red;
+ if (((channel & GreenChannel) != 0) && (maximum < histogram[x].green))
+ maximum=histogram[x].green;
+ if (((channel & BlueChannel) != 0) && (maximum < histogram[x].blue))
+ maximum=histogram[x].blue;
+ }
+ scale=(MagickRealType) histogram_image->rows/maximum;
/*
- Initialize color description tree.
+ Initialize histogram image.
*/
- 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++)
+ exception=(&image->exception);
+ (void) QueryColorDatabase("#000000",&histogram_image->background_color,
+ &image->exception);
+ (void) SetImageBackgroundColor(histogram_image);
+ for (x=0; x < (ssize_t) histogram_image->columns; x++)
{
- p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
- if (p == (const PixelPacket *) NULL)
+ q=GetAuthenticPixels(histogram_image,x,0,1,histogram_image->rows,exception);
+ if (q == (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++)
+ if ((channel & RedChannel) != 0)
{
- 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
+ y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].red-0.5);
+ r=q+y;
+ for ( ; y < (ssize_t) histogram_image->rows; y++)
{
- /*
- 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;
+ r->red=(Quantum) QuantumRange;
+ r++;
}
- 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);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% M i n M a x S t r e t c h I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% MinMaxStretchImage() uses the exact minimum and maximum values found in
-% each of the channels given, as the BlackPoint and WhitePoint to linearly
-% stretch the colors (and histogram) of the image. The stretch points are
-% also moved further inward by the adjustment values given.
-%
-% If the adjustment values are both zero this function is equivelent to a
-% perfect normalization (or autolevel) of the image.
-%
-% Each channel is stretched independantally of each other (producing color
-% distortion) unless the special 'SyncChannels' flag is also provided in the
-% channels setting. If this flag is present the minimum and maximum point
-% will be extracted from all the given channels, and those channels will be
-% stretched by exactly the same amount (preventing color distortion).
-%
-% In the special case that only ONE value is found in a channel of the image
-% that value is not stretched, that value is left as is.
-%
-% The 'SyncChannels' is turned on in the 'DefaultChannels' setting by
-% default.
-%
-% The format of the MinMaxStretchImage method is:
-%
-% MagickBooleanType MinMaxStretchImage(Image *image,
-% const ChannelType channel, const double black_adjust,
-% const double white_adjust)
-%
-% A description of each parameter follows:
-%
-% o image: The image to auto-level
-%
-% o channel: The channels to auto-level. If the special 'SyncChannels'
-% flag is set, all the given channels are stretched by the same amount.
-%
-% o black_adjust, white_adjust: Move the Black/White Point inward
-% 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)
-{
- double
- min,max;
-
- MagickStatusType
- status;
-
- status=MagickTrue;
- if ((channel & SyncChannels) != 0)
- {
- /*
- Auto-level all channels equally.
- */
- (void) GetImageChannelRange(image,channel,&min,&max,&image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status = LevelImageChannel(image,channel,min,max,1.0);
- return(status);
- }
- /*
- Auto-level each channel separately.
- */
- if ((channel & RedChannel) != 0)
- {
- (void) GetImageChannelRange(image,RedChannel,&min,&max,&image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status&=LevelImageChannel(image,RedChannel,min,max,1.0);
- }
- if ((channel & GreenChannel) != 0)
- {
- (void) GetImageChannelRange(image,GreenChannel,&min,&max,
- &image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status&=LevelImageChannel(image,GreenChannel,min,max,1.0);
- }
- if ((channel & BlueChannel) != 0)
- {
- (void) GetImageChannelRange(image,BlueChannel,&min,&max,
- &image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status&=LevelImageChannel(image,BlueChannel,min,max,1.0);
- }
- if (((channel & OpacityChannel) != 0) &&
- (image->matte == MagickTrue))
- {
- (void) GetImageChannelRange(image,OpacityChannel,&min,&max,
- &image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status&=LevelImageChannel(image,OpacityChannel,min,max,1.0);
- }
- if (((channel & IndexChannel) != 0) &&
- (image->colorspace == CMYKColorspace))
- {
- (void) GetImageChannelRange(image,IndexChannel,&min,&max,
- &image->exception);
- min+=black_value;
- max-=white_value;
- if ( fabs(min-max) >= MagickEpsilon )
- status&=LevelImageChannel(image,IndexChannel,min,max,1.0);
- }
- return(status);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% 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;
-
- MagickBooleanType
- status;
-
- 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)
+ if ((channel & GreenChannel) != 0)
{
- (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
- ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
+ y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].green-0.5);
+ r=q+y;
+ for ( ; y < (ssize_t) histogram_image->rows; y++)
+ {
+ r->green=(Quantum) QuantumRange;
+ r++;
+ }
}
- (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)
+ if ((channel & BlueChannel) != 0)
{
- MagickBooleanType
- proceed;
-
- proceed=SetImageProgress(image,HistogramImageTag,i,number_colors);
- if (proceed == MagickFalse)
- status=MagickFalse;
+ y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].blue-0.5);
+ r=q+y;
+ for ( ; y < (ssize_t) histogram_image->rows; y++)
+ {
+ r->blue=(Quantum) QuantumRange;
+ r++;
+ }
}
- p++;
+ if (SyncAuthenticPixels(histogram_image,exception) == MagickFalse)
+ break;
+ status=SetImageProgress(image,SaveImageTag,y,histogram_image->rows);
+ if (status == MagickFalse)
+ break;
}
- (void) fflush(file);
- histogram=(ColorPacket *) RelinquishMagickMemory(histogram);
- return(number_colors);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% 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"
-
- MagickBooleanType
- status;
-
- register long
- i;
-
- unsigned long
- number_children;
-
/*
- Traverse any children.
+ Relinquish resources.
*/
- 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))
+ histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
+ option=GetImageOption(image_info,"histogram:unique-colors");
+ if ((option == (const char *) NULL) || (IsMagickTrue(option) != MagickFalse))
{
- register ColorPacket
- *p;
-
- register IndexPacket
- *restrict indexes;
+ FILE
+ *file;
- register PixelPacket
- *restrict q;
+ int
+ unique_file;
- 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)
+ /*
+ Add a unique colors as an image comment.
+ */
+ file=(FILE *) NULL;
+ unique_file=AcquireUniqueFileResource(filename);
+ if (unique_file != -1)
+ file=fdopen(unique_file,"wb");
+ if ((unique_file != -1) && (file != (FILE *) NULL))
{
- MagickBooleanType
- proceed;
+ char
+ *property;
- proceed=SetImageProgress(image,UniqueColorsImageTag,
- cube_info->progress,cube_info->colors);
- if (proceed == MagickFalse)
- status=MagickFalse;
+ (void) GetNumberColors(image,file,&image->exception);
+ (void) fclose(file);
+ property=FileToString(filename,~0UL,&image->exception);
+ if (property != (char *) NULL)
+ {
+ (void) SetImageProperty(histogram_image,"comment",property);
+ property=DestroyString(property);
+ }
}
- cube_info->progress++;
+ (void) RelinquishUniqueFileResource(filename);
}
-}
-
-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);
+ /*
+ Write Histogram image.
+ */
+ (void) CopyMagickString(histogram_image->filename,image_info->filename,
+ MaxTextExtent);
+ write_info=CloneImageInfo(image_info);
+ (void) SetImageInfo(write_info,1,&image->exception);
+ if (LocaleCompare(write_info->magick,"HISTOGRAM") == 0)
+ (void) FormatMagickString(histogram_image->filename,MaxTextExtent,
+ "miff:%s",write_info->filename);
+ status=WriteImage(write_info,histogram_image);
+ histogram_image=DestroyImage(histogram_image);
+ write_info=DestroyImageInfo(write_info);
+ return(status);
}