/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% SSSSS TTTTT AAA TTTTT IIIII SSSSS TTTTT IIIII CCCC %
% SS T A A T I SS T I C %
% SSS T AAAAA T I SSS T I C %
% SS T A A T I SS T I C %
% SSSSS T A A T IIIII SSSSS T IIIII CCCC %
% %
% %
% ImageMagick Image Methods %
% %
% Software Design %
% John Cristy %
% July 1992 %
% %
% %
% Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% http://www.imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
*/
/*
Include declarations.
*/
#include "magick/studio.h"
#include "magick/property.h"
#include "magick/animate.h"
#include "magick/blob.h"
#include "magick/blob-private.h"
#include "magick/cache.h"
#include "magick/cache-private.h"
#include "magick/client.h"
#include "magick/color.h"
#include "magick/color-private.h"
#include "magick/colorspace.h"
#include "magick/colorspace-private.h"
#include "magick/composite.h"
#include "magick/composite-private.h"
#include "magick/compress.h"
#include "magick/constitute.h"
#include "magick/deprecate.h"
#include "magick/display.h"
#include "magick/draw.h"
#include "magick/enhance.h"
#include "magick/exception.h"
#include "magick/exception-private.h"
#include "magick/gem.h"
#include "magick/geometry.h"
#include "magick/list.h"
#include "magick/image-private.h"
#include "magick/magic.h"
#include "magick/magick.h"
#include "magick/memory_.h"
#include "magick/module.h"
#include "magick/monitor.h"
#include "magick/option.h"
#include "magick/paint.h"
#include "magick/pixel-private.h"
#include "magick/profile.h"
#include "magick/quantize.h"
#include "magick/random_.h"
#include "magick/segment.h"
#include "magick/semaphore.h"
#include "magick/signature.h"
#include "magick/statistic.h"
#include "magick/string_.h"
#include "magick/timer.h"
#include "magick/utility.h"
#include "magick/version.h"
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t I m a g e B o u n d i n g B o x %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageBoundingBox() returns the bounding box of an image canvas.
%
% The format of the GetImageBoundingBox method is:
%
% RectangleInfo GetImageBoundingBox(const Image *image,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o bounds: Method GetImageBoundingBox returns the bounding box of an
% image canvas.
%
% o image: The image.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
ExceptionInfo *exception)
{
long
y;
MagickPixelPacket
target[3],
pixel;
RectangleInfo
bounds;
register const PixelPacket
*p;
register IndexPacket
*indexes;
register long
x;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
bounds.width=0;
bounds.height=0;
bounds.x=(long) image->columns;
bounds.y=(long) image->rows;
GetMagickPixelPacket(image,&target[0]);
p=AcquireImagePixels(image,0,0,1,1,exception);
if (p == (const PixelPacket *) NULL)
return(bounds);
SetMagickPixelPacket(image,p,GetIndexes(image),&target[0]);
GetMagickPixelPacket(image,&target[1]);
p=AcquireImagePixels(image,(long) image->columns-1,0,1,1,exception);
SetMagickPixelPacket(image,p,GetIndexes(image),&target[1]);
GetMagickPixelPacket(image,&target[2]);
p=AcquireImagePixels(image,0,(long) image->rows-1,1,1,exception);
SetMagickPixelPacket(image,p,GetIndexes(image),&target[2]);
GetMagickPixelPacket(image,&pixel);
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=GetIndexes(image);
for (x=0; x < (long) image->columns; x++)
{
SetMagickPixelPacket(image,p,indexes+x,&pixel);
if ((x < bounds.x) &&
(IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
bounds.x=x;
if ((x > (long) bounds.width) &&
(IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
bounds.width=(unsigned long) x;
if ((y < bounds.y) &&
(IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
bounds.y=y;
if ((y > (long) bounds.height) &&
(IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
bounds.height=(unsigned long) y;
p++;
}
}
if ((bounds.width == 0) || (bounds.height == 0))
(void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
"GeometryDoesNotContainImage","`%s'",image->filename);
else
{
bounds.width-=(bounds.x-1);
bounds.height-=(bounds.y-1);
}
return(bounds);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t I m a g e C h a n n e l D e p t h %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageChannelDepth() returns the depth of a particular image channel.
%
% The format of the GetImageChannelDepth method is:
%
% unsigned long GetImageChannelDepth(const Image *image,
% const ChannelType channel,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o channel: The channel.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport unsigned long GetImageDepth(const Image *image,
ExceptionInfo *exception)
{
return(GetImageChannelDepth(image,AllChannels,exception));
}
MagickExport unsigned long GetImageChannelDepth(const Image *image,
const ChannelType channel,ExceptionInfo *exception)
{
long
y;
MagickStatusType
status;
register const IndexPacket
*indexes;
register const PixelPacket
*p;
register long
x;
unsigned long
depth;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
depth=1;
if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
{
p=image->colormap;
for (x=0; x < (long) image->colors; )
{
status=MagickFalse;
if ((channel & RedChannel) != 0)
status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
depth),depth);
if ((channel & GreenChannel) != 0)
status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
depth),depth);
if ((channel & BlueChannel) != 0)
status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
depth),depth);
if (status != MagickFalse)
{
depth++;
if (depth == QuantumDepth)
return(depth);
continue;
}
x++;
p++;
}
}
else
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=AcquireIndexes(image);
for (x=0; x < (long) image->columns; )
{
status=MagickFalse;
if ((channel & RedChannel) != 0)
status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
depth),depth);
if ((channel & GreenChannel) != 0)
status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
depth),depth);
if ((channel & BlueChannel) != 0)
status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
depth),depth);
if ((channel & OpacityChannel) != 0)
status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
depth),depth);
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
depth),depth);
if (status != MagickFalse)
{
depth++;
if (depth == QuantumDepth)
return(depth);
continue;
}
x++;
p++;
}
}
return(depth);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t I m a g e C h a n n e l E x t r e m a %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageChannelExtrema() returns the extrema of one or more image channels.
%
% The format of the GetImageChannelExtrema method is:
%
% MagickBooleanType GetImageChannelExtrema(const Image *image,
% const ChannelType channel,unsigned long *minima,unsigned long *maxima,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o channel: The channel.
%
% o minima: The minimum value in the channel.
%
% o maxima: The maximum value in the channel.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType GetImageExtrema(const Image *image,
unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
{
return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
}
MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
const ChannelType channel,unsigned long *minima,unsigned long *maxima,
ExceptionInfo *exception)
{
double
max,
min;
MagickBooleanType
status;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
status=GetImageChannelRange(image,channel,&min,&max,exception);
*minima=(unsigned long) (min+0.5);
*maxima=(unsigned long) (max+0.5);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t I m a g e C h a n n e l M e a n %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageChannelMean() returns the mean and standard deviation of one or more
% image channels.
%
% The format of the GetImageChannelMean method is:
%
% MagickBooleanType GetImageChannelMean(const Image *image,
% const ChannelType channel,double *mean,double *standard_deviation,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o channel: The channel.
%
% o mean: The average value in the channel.
%
% o standard_deviation: The standard deviation of the channel.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
double *standard_deviation,ExceptionInfo *exception)
{
MagickBooleanType
status;
status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
exception);
return(status);
}
MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
const ChannelType channel,double *mean,double *standard_deviation,
ExceptionInfo *exception)
{
#define PixelSquared(x) ((x)*(x))
double
area;
long
y;
register const IndexPacket
*indexes;
register const PixelPacket
*p;
register long
x;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
*mean=0.0;
*standard_deviation=0.0;
area=0.0;
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=AcquireIndexes(image);
for (x=0; x < (long) image->columns; x++)
{
if ((channel & RedChannel) != 0)
{
*mean+=p->red;
*standard_deviation+=(double) p->red*p->red;
area++;
}
if ((channel & GreenChannel) != 0)
{
*mean+=p->green;
*standard_deviation+=(double) p->green*p->green;
area++;
}
if ((channel & BlueChannel) != 0)
{
*mean+=p->blue;
*standard_deviation+=(double) p->blue*p->blue;
area++;
}
if ((channel & OpacityChannel) != 0)
{
*mean+=p->opacity;
*standard_deviation+=(double) p->opacity*p->opacity;
area++;
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
*mean+=indexes[x];
*standard_deviation+=(double) indexes[x]*indexes[x];
area++;
}
p++;
}
}
if (y < (long) image->rows)
return(MagickFalse);
if (area != 0)
{
*mean/=area;
*standard_deviation/=area;
}
*standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
return(y == (long) image->rows ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t I m a g e C h a n n e l R a n g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageChannelRange() returns the range of one or more image channels.
%
% The format of the GetImageChannelRange method is:
%
% MagickBooleanType GetImageChannelRange(const Image *image,
% const ChannelType channel,double *minima,double *maxima,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o channel: The channel.
%
% o minima: The minimum value in the channel.
%
% o maxima: The maximum value in the channel.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType GetImageRange(const Image *image,
double *minima,double *maxima,ExceptionInfo *exception)
{
return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
}
MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
const ChannelType channel,double *minima,double *maxima,
ExceptionInfo *exception)
{
long
y;
MagickPixelPacket
pixel;
register const IndexPacket
*indexes;
register const PixelPacket
*p;
register long
x;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
*maxima=(-1.0E-37);
*minima=1.0E+37;
GetMagickPixelPacket(image,&pixel);
y=(long) image->rows;
if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
{
p=image->colormap;
for (x=0; x < (long) image->colors; )
{
if ((channel & RedChannel) != 0)
{
if ((double) p->red < *minima)
*minima=(double) p->red;
if ((double) p->red > *maxima)
*maxima=(double) p->red;
}
if ((channel & GreenChannel) != 0)
{
if ((double) p->green < *minima)
*minima=(double) p->green;
if ((double) p->green > *maxima)
*maxima=(double) p->green;
}
if ((channel & BlueChannel) != 0)
{
if ((double) p->blue < *minima)
*minima=(double) p->blue;
if ((double) p->blue > *maxima)
*maxima=(double) p->blue;
}
x++;
p++;
}
}
else
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=AcquireIndexes(image);
for (x=0; x < (long) image->columns; )
{
SetMagickPixelPacket(image,p,indexes+x,&pixel);
if ((channel & RedChannel) != 0)
{
if (pixel.red < *minima)
*minima=(double) pixel.red;
if (pixel.red > *maxima)
*maxima=(double) pixel.red;
}
if ((channel & GreenChannel) != 0)
{
if (pixel.green < *minima)
*minima=(double) pixel.green;
if (pixel.green > *maxima)
*maxima=(double) pixel.green;
}
if ((channel & BlueChannel) != 0)
{
if (pixel.blue < *minima)
*minima=(double) pixel.blue;
if (pixel.blue > *maxima)
*maxima=(double) pixel.blue;
}
if ((channel & OpacityChannel) != 0)
{
if (pixel.opacity < *minima)
*minima=(double) pixel.opacity;
if (pixel.opacity > *maxima)
*maxima=(double) pixel.opacity;
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
{
if ((double) indexes[x] < *minima)
*minima=(double) indexes[x];
if ((double) indexes[x] > *maxima)
*maxima=(double) indexes[x];
}
x++;
p++;
}
}
return(y == (long) image->rows ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t I m a g e C h a n n e l S t a t i s t i c s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageChannelStatistics() returns statistics for each channel in the
% image. The statistics incude the channel depth, its minima and
% maxima, the mean, and the standard deviation. You can access the red
% channel mean, for example, like this:
%
% channel_statistics=GetImageChannelStatistics(image,excepton);
% red_mean=channel_statistics[RedChannel].mean;
%
% Use MagickRelinquishMemory() to free the statistics buffer.
%
% The format of the GetImageChannelStatistics method is:
%
% ChannelStatistics *GetImageChannelStatistics(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 double MagickMax(const double x,const double y)
{
if (x > y)
return(x);
return(y);
}
static inline double MagickMin(const double x,const double y)
{
if (x < y)
return(x);
return(y);
}
MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
ExceptionInfo *exception)
{
ChannelStatistics
*channel_statistics;
double
area;
long
y;
MagickStatusType
status;
register const IndexPacket
*indexes;
register const PixelPacket
*p;
register long
i,
x;
size_t
length;
unsigned long
channels,
depth;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
length=AllChannels+1UL;
channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
sizeof(*channel_statistics));
if (channel_statistics == (ChannelStatistics *) NULL)
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
(void) ResetMagickMemory(channel_statistics,0,length);
for (i=0; i <= AllChannels; i++)
{
channel_statistics[i].depth=1;
channel_statistics[i].maxima=(-1.0E-37);
channel_statistics[i].minima=1.0E+37;
channel_statistics[i].mean=0.0;
channel_statistics[i].standard_deviation=0.0;
}
y=(long) image->rows;
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=AcquireIndexes(image);
for (x=0; x < (long) image->columns; )
{
if (channel_statistics[RedChannel].depth != QuantumDepth)
{
depth=channel_statistics[RedChannel].depth;
status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
depth),depth) ? MagickTrue : MagickFalse;
if (status != MagickFalse)
{
channel_statistics[RedChannel].depth++;
continue;
}
}
if (channel_statistics[GreenChannel].depth != QuantumDepth)
{
depth=channel_statistics[GreenChannel].depth;
status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
depth),depth) ? MagickTrue : MagickFalse;
if (status != MagickFalse)
{
channel_statistics[GreenChannel].depth++;
continue;
}
}
if (channel_statistics[BlueChannel].depth != QuantumDepth)
{
depth=channel_statistics[BlueChannel].depth;
status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
depth),depth) ? MagickTrue : MagickFalse;
if (status != MagickFalse)
{
channel_statistics[BlueChannel].depth++;
continue;
}
}
if (channel_statistics[OpacityChannel].depth != QuantumDepth)
{
depth=channel_statistics[OpacityChannel].depth;
status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
p->opacity,depth),depth) ? MagickTrue : MagickFalse;
if (status != MagickFalse)
{
channel_statistics[OpacityChannel].depth++;
continue;
}
}
if (image->colorspace == CMYKColorspace)
{
if (channel_statistics[BlackChannel].depth != QuantumDepth)
{
depth=channel_statistics[BlackChannel].depth;
status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
indexes[x],depth),depth) ? MagickTrue : MagickFalse;
if (status != MagickFalse)
{
channel_statistics[BlackChannel].depth++;
continue;
}
}
}
if ((double) p->red < channel_statistics[RedChannel].minima)
channel_statistics[RedChannel].minima=(double) p->red;
if ((double) p->red > channel_statistics[RedChannel].maxima)
channel_statistics[RedChannel].maxima=(double) p->red;
channel_statistics[RedChannel].mean+=p->red;
channel_statistics[RedChannel].standard_deviation+=(double)
p->red*p->red;
if ((double) p->green < channel_statistics[GreenChannel].minima)
channel_statistics[GreenChannel].minima=(double) p->green;
if ((double) p->green > channel_statistics[GreenChannel].maxima)
channel_statistics[GreenChannel].maxima=(double) p->green;
channel_statistics[GreenChannel].mean+=p->green;
channel_statistics[GreenChannel].standard_deviation+=(double)
p->green*p->green;
if ((double) p->blue < channel_statistics[BlueChannel].minima)
channel_statistics[BlueChannel].minima=(double) p->blue;
if ((double) p->blue > channel_statistics[BlueChannel].maxima)
channel_statistics[BlueChannel].maxima=(double) p->blue;
channel_statistics[BlueChannel].mean+=p->blue;
channel_statistics[BlueChannel].standard_deviation+=(double)
p->blue*p->blue;
if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
channel_statistics[OpacityChannel].minima=(double) p->opacity;
if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
channel_statistics[OpacityChannel].maxima=(double) p->opacity;
channel_statistics[OpacityChannel].mean+=p->opacity;
channel_statistics[OpacityChannel].standard_deviation+=(double)
p->opacity*p->opacity;
if (image->colorspace == CMYKColorspace)
{
if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
channel_statistics[BlackChannel].minima=(double) indexes[x];
if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
channel_statistics[BlackChannel].maxima=(double) indexes[x];
channel_statistics[BlackChannel].mean+=indexes[x];
channel_statistics[BlackChannel].standard_deviation+=(double)
indexes[x]*indexes[x];
}
x++;
p++;
}
}
area=(double) image->columns*image->rows;
for (i=0; i < AllChannels; i++)
{
channel_statistics[i].mean/=area;
channel_statistics[i].standard_deviation/=area;
}
for (i=0; i < AllChannels; i++)
{
channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double)
channel_statistics[AllChannels].depth,(double)
channel_statistics[i].depth);
channel_statistics[AllChannels].minima=MagickMin(
channel_statistics[AllChannels].minima,channel_statistics[i].minima);
channel_statistics[AllChannels].maxima=MagickMax(
channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
channel_statistics[AllChannels].standard_deviation+=
channel_statistics[i].standard_deviation;
}
channels=4;
if (image->colorspace == CMYKColorspace)
channels++;
channel_statistics[AllChannels].mean/=channels;
channel_statistics[AllChannels].standard_deviation/=channels;
for (i=0; i <= AllChannels; i++)
channel_statistics[i].standard_deviation=sqrt(
channel_statistics[i].standard_deviation-
(channel_statistics[i].mean*channel_statistics[i].mean));
return(channel_statistics);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t I m a g e Q u a n t u m D e p t h %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetImageQuantumDepth() returns the depth of the image rounded to a legal
% quantum depth: 8, 16, or 32.
%
% The format of the GetImageQuantumDepth method is:
%
% unsigned long GetImageQuantumDepth(const Image *image,
% const MagickBooleanType constrain)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o constrain: A value other than MagickFalse, constrains the depth to
% a maximum of QuantumDepth.
%
*/
MagickExport unsigned long GetImageQuantumDepth(const Image *image,
const MagickBooleanType constrain)
{
unsigned long
depth;
depth=image->depth;
if (depth <= 8)
depth=8;
else
if (depth <= 16)
depth=16;
if (constrain != MagickFalse)
depth=(unsigned long) MagickMin((double) depth,(double) QuantumDepth);
return(depth);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% S e t I m a g e C h a n n e l D e p t h %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SetImageChannelDepth() sets the depth of the image.
%
% The format of the SetImageChannelDepth method is:
%
% MagickBooleanType SetImageChannelDepth(Image *image,
% const ChannelType channel,const unsigned long depth)
%
% A description of each parameter follows:
%
% o image: The image.
%
% o channel: The channel.
%
% o depth: The image depth.
%
*/
MagickExport MagickBooleanType SetImageDepth(Image *image,
const unsigned long depth)
{
return(SetImageChannelDepth(image,AllChannels,depth));
}
MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
const ChannelType channel,const unsigned long depth)
{
long
y;
register IndexPacket
*indexes;
register long
x;
register PixelPacket
*q;
assert(image != (Image *) NULL);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(image->signature == MagickSignature);
y=(long) image->rows;
if (GetImageDepth(image,&image->exception) >
(unsigned long) MagickMin((double) depth,(double) QuantumDepth))
{
/*
Scale pixels to desired depth.
*/
for (y=0; y < (long) image->rows; y++)
{
q=GetImagePixels(image,0,y,image->columns,1);
if (q == (PixelPacket *) NULL)
break;
indexes=GetIndexes(image);
for (x=0; x < (long) image->columns; x++)
{
if ((channel & RedChannel) != 0)
q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,depth),depth);
if ((channel & GreenChannel) != 0)
q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,depth),depth);
if ((channel & BlueChannel) != 0)
q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,depth),depth);
if ((channel & OpacityChannel) != 0)
q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,depth),
depth);
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],depth),
depth);
q++;
}
if (SyncImagePixels(image) == MagickFalse)
break;
}
if (image->storage_class == PseudoClass)
{
register long
i;
q=image->colormap;
for (i=0; i < (long) image->colors; i++)
{
if ((channel & RedChannel) != 0)
q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,depth),depth);
if ((channel & GreenChannel) != 0)
q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,depth),
depth);
if ((channel & BlueChannel) != 0)
q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,depth),depth);
if ((channel & OpacityChannel) != 0)
q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,depth),
depth);
q++;
}
}
}
image->depth=depth;
return(y == (long) image->rows ? MagickTrue : MagickFalse);
}
|