{
#define LevelImageTag "Level/Image"
#define LevelValue(x) (ClampToQuantum((MagickRealType) QuantumRange* \
- pow(((double) (x)-black_point)/(white_point-black_point),1.0/gamma)))
+ pow(scale*((double)(x)-black_point),1.0/gamma)))
CacheView
*image_view;
register long
i;
+ register double
+ scale;
+
/*
Allocate and initialize levels map.
*/
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+ scale = (white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
if (image->storage_class == PseudoClass)
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(dynamic,4) shared(progress,status)
q->blue=LevelValue(q->blue);
if (((channel & OpacityChannel) != 0) &&
(image->matte == MagickTrue))
- q->opacity=LevelValue(q->opacity);
+ q->opacity=QuantumRange-LevelValue(QuantumRange-q->opacity);
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
indexes[x]=LevelValue(indexes[x]);
% 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.
%
% 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)
{
MagickStatusType
status;
+ status=MagickTrue;
if ((channel & SyncChannels) != 0)
{
/*
(void) GetImageChannelRange(image,channel,&min,&max,&image->exception);
min+=black_value;
max-=white_value;
- return(LevelImageChannel(image,channel,min,max,1.0));
+ if ( fabs(min-max) >= MagickEpsilon )
+ status = LevelImageChannel(image,channel,min,max,1.0);
+ return(status);
}
/*
Auto-level each channel separately.
*/
- status=MagickTrue;
if ((channel & RedChannel) != 0)
{
(void) GetImageChannelRange(image,RedChannel,&min,&max,&image->exception);
min+=black_value;
max-=white_value;
- status&=LevelImageChannel(image,RedChannel,min,max,1.0);
+ if ( fabs(min-max) >= MagickEpsilon )
+ status&=LevelImageChannel(image,RedChannel,min,max,1.0);
}
if ((channel & GreenChannel) != 0)
{
&image->exception);
min+=black_value;
max-=white_value;
- status&=LevelImageChannel(image,GreenChannel,min,max,1.0);
+ if ( fabs(min-max) >= MagickEpsilon )
+ status&=LevelImageChannel(image,GreenChannel,min,max,1.0);
}
if ((channel & BlueChannel) != 0)
{
&image->exception);
min+=black_value;
max-=white_value;
- status&=LevelImageChannel(image,BlueChannel,min,max,1.0);
+ if ( fabs(min-max) >= MagickEpsilon )
+ status&=LevelImageChannel(image,BlueChannel,min,max,1.0);
}
if (((channel & OpacityChannel) != 0) &&
(image->matte == MagickTrue))
&image->exception);
min+=black_value;
max-=white_value;
- status&=LevelImageChannel(image,OpacityChannel,min,max,1.0);
+ if ( fabs(min-max) >= MagickEpsilon )
+ status&=LevelImageChannel(image,OpacityChannel,min,max,1.0);
}
if (((channel & IndexChannel) != 0) &&
(image->colorspace == CMYKColorspace))
&image->exception);
min+=black_value;
max-=white_value;
- status&=LevelImageChannel(image,IndexChannel,min,max,1.0);
+ if ( fabs(min-max) >= MagickEpsilon )
+ status&=LevelImageChannel(image,IndexChannel,min,max,1.0);
}
- return(status != 0 ? MagickTrue : MagickFalse);
+ return(status);
}
\f
/*