You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1731 lines
54 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% GGGG EEEEE M M %
% G E MM MM %
% G GG EEE M M M %
% G G E M M %
% GGGG EEEEE M M %
% %
% %
% Graphic Gems - Graphic Support Methods %
% %
% Software Design %
% Cristy %
% August 1996 %
% %
% %
% Copyright 1999-2021 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 %
% %
% https://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 "MagickCore/studio.h"
#include "MagickCore/color-private.h"
#include "MagickCore/draw.h"
#include "MagickCore/gem.h"
#include "MagickCore/gem-private.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/log.h"
#include "MagickCore/memory_.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/pixel-private.h"
#include "MagickCore/quantum.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/random_.h"
#include "MagickCore/resize.h"
#include "MagickCore/transform.h"
#include "MagickCore/signature-private.h"
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H C L T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHCLToRGB() transforms a (hue, chroma, luma) to a (red, green,
% blue) triple.
%
% The format of the ConvertHCLToRGBImage method is:
%
% void ConvertHCLToRGB(const double hue,const double chroma,
% const double luma,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, chroma, luma: A double value representing a component of the
% HCL color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHCLToRGB(const double hue,const double chroma,
const double luma,double *red,double *green,double *blue)
{
double
b,
c,
g,
h,
m,
r,
x;
/*
Convert HCL to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
h=6.0*hue;
c=chroma;
x=c*(1.0-fabs(fmod(h,2.0)-1.0));
r=0.0;
g=0.0;
b=0.0;
if ((0.0 <= h) && (h < 1.0))
{
r=c;
g=x;
}
else
if ((1.0 <= h) && (h < 2.0))
{
r=x;
g=c;
}
else
if ((2.0 <= h) && (h < 3.0))
{
g=c;
b=x;
}
else
if ((3.0 <= h) && (h < 4.0))
{
g=x;
b=c;
}
else
if ((4.0 <= h) && (h < 5.0))
{
r=x;
b=c;
}
else
if ((5.0 <= h) && (h < 6.0))
{
r=c;
b=x;
}
m=luma-(0.298839*r+0.586811*g+0.114350*b);
*red=QuantumRange*(r+m);
*green=QuantumRange*(g+m);
*blue=QuantumRange*(b+m);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H C L p T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHCLpToRGB() transforms a (hue, chroma, luma) to a (red, green,
% blue) triple. Since HCL colorspace is wider than RGB, we instead choose a
% saturation strategy to project it on the RGB cube.
%
% The format of the ConvertHCLpToRGBImage method is:
%
% void ConvertHCLpToRGB(const double hue,const double chroma,
% const double luma,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, chroma, luma: A double value representing a componenet of the
% HCLp color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHCLpToRGB(const double hue,const double chroma,
const double luma,double *red,double *green,double *blue)
{
double
b,
c,
g,
h,
m,
r,
x,
z;
/*
Convert HCLp to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
h=6.0*hue;
c=chroma;
x=c*(1.0-fabs(fmod(h,2.0)-1.0));
r=0.0;
g=0.0;
b=0.0;
if ((0.0 <= h) && (h < 1.0))
{
r=c;
g=x;
}
else
if ((1.0 <= h) && (h < 2.0))
{
r=x;
g=c;
}
else
if ((2.0 <= h) && (h < 3.0))
{
g=c;
b=x;
}
else
if ((3.0 <= h) && (h < 4.0))
{
g=x;
b=c;
}
else
if ((4.0 <= h) && (h < 5.0))
{
r=x;
b=c;
}
else
if ((5.0 <= h) && (h < 6.0))
{
r=c;
b=x;
}
m=luma-(0.298839*r+0.586811*g+0.114350*b);
z=1.0;
if (m < 0.0)
{
z=luma/(luma-m);
m=0.0;
}
else
if (m+c > 1.0)
{
z=(1.0-luma)/(m+c-luma);
m=1.0-z*c;
}
*red=QuantumRange*(z*r+m);
*green=QuantumRange*(z*g+m);
*blue=QuantumRange*(z*b+m);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H S B T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
% green, blue) triple.
%
% The format of the ConvertHSBToRGBImage method is:
%
% void ConvertHSBToRGB(const double hue,const double saturation,
% const double brightness,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, saturation, brightness: A double value representing a
% component of the HSB color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
const double brightness,double *red,double *green,double *blue)
{
double
f,
h,
p,
q,
t;
/*
Convert HSB to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
if (fabs(saturation) < MagickEpsilon)
{
*red=QuantumRange*brightness;
*green=(*red);
*blue=(*red);
return;
}
h=6.0*(hue-floor(hue));
f=h-floor((double) h);
p=brightness*(1.0-saturation);
q=brightness*(1.0-saturation*f);
t=brightness*(1.0-(saturation*(1.0-f)));
switch ((int) h)
{
case 0:
default:
{
*red=QuantumRange*brightness;
*green=QuantumRange*t;
*blue=QuantumRange*p;
break;
}
case 1:
{
*red=QuantumRange*q;
*green=QuantumRange*brightness;
*blue=QuantumRange*p;
break;
}
case 2:
{
*red=QuantumRange*p;
*green=QuantumRange*brightness;
*blue=QuantumRange*t;
break;
}
case 3:
{
*red=QuantumRange*p;
*green=QuantumRange*q;
*blue=QuantumRange*brightness;
break;
}
case 4:
{
*red=QuantumRange*t;
*green=QuantumRange*p;
*blue=QuantumRange*brightness;
break;
}
case 5:
{
*red=QuantumRange*brightness;
*green=QuantumRange*p;
*blue=QuantumRange*q;
break;
}
}
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H S I T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHSIToRGB() transforms a (hue, saturation, intensity) to a (red,
% green, blue) triple.
%
% The format of the ConvertHSIToRGBImage method is:
%
% void ConvertHSIToRGB(const double hue,const double saturation,
% const double intensity,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, saturation, intensity: A double value representing a
% component of the HSI color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHSIToRGB(const double hue,const double saturation,
const double intensity,double *red,double *green,double *blue)
{
double
b,
g,
h,
r;
/*
Convert HSI to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
h=360.0*hue;
h-=360.0*floor(h/360.0);
if (h < 120.0)
{
b=intensity*(1.0-saturation);
r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
g=3.0*intensity-r-b;
}
else
if (h < 240.0)
{
h-=120.0;
r=intensity*(1.0-saturation);
g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
b=3.0*intensity-r-g;
}
else
{
h-=240.0;
g=intensity*(1.0-saturation);
b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
r=3.0*intensity-g-b;
}
*red=QuantumRange*r;
*green=QuantumRange*g;
*blue=QuantumRange*b;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H S L T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
% green, blue) triple.
%
% The format of the ConvertHSLToRGBImage method is:
%
% void ConvertHSLToRGB(const double hue,const double saturation,
% const double lightness,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, saturation, lightness: A double value representing a
% component of the HSL color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
const double lightness,double *red,double *green,double *blue)
{
double
c,
h,
min,
x;
/*
Convert HSL to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
h=hue*360.0;
if (lightness <= 0.5)
c=2.0*lightness*saturation;
else
c=(2.0-2.0*lightness)*saturation;
min=lightness-0.5*c;
h-=360.0*floor(h/360.0);
h/=60.0;
x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
switch ((int) floor(h))
{
case 0:
{
*red=QuantumRange*(min+c);
*green=QuantumRange*(min+x);
*blue=QuantumRange*min;
break;
}
case 1:
{
*red=QuantumRange*(min+x);
*green=QuantumRange*(min+c);
*blue=QuantumRange*min;
break;
}
case 2:
{
*red=QuantumRange*min;
*green=QuantumRange*(min+c);
*blue=QuantumRange*(min+x);
break;
}
case 3:
{
*red=QuantumRange*min;
*green=QuantumRange*(min+x);
*blue=QuantumRange*(min+c);
break;
}
case 4:
{
*red=QuantumRange*(min+x);
*green=QuantumRange*min;
*blue=QuantumRange*(min+c);
break;
}
case 5:
{
*red=QuantumRange*(min+c);
*green=QuantumRange*min;
*blue=QuantumRange*(min+x);
break;
}
default:
{
*red=0.0;
*green=0.0;
*blue=0.0;
}
}
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H S V T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHSVToRGB() transforms a (hue, saturation, value) to a (red,
% green, blue) triple.
%
% The format of the ConvertHSVToRGBImage method is:
%
% void ConvertHSVToRGB(const double hue,const double saturation,
% const double value,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, saturation, value: A double value representing a
% component of the HSV color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHSVToRGB(const double hue,const double saturation,
const double value,double *red,double *green,double *blue)
{
double
c,
h,
min,
x;
/*
Convert HSV to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
h=hue*360.0;
c=value*saturation;
min=value-c;
h-=360.0*floor(h/360.0);
h/=60.0;
x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
switch ((int) floor(h))
{
case 0:
{
*red=QuantumRange*(min+c);
*green=QuantumRange*(min+x);
*blue=QuantumRange*min;
break;
}
case 1:
{
*red=QuantumRange*(min+x);
*green=QuantumRange*(min+c);
*blue=QuantumRange*min;
break;
}
case 2:
{
*red=QuantumRange*min;
*green=QuantumRange*(min+c);
*blue=QuantumRange*(min+x);
break;
}
case 3:
{
*red=QuantumRange*min;
*green=QuantumRange*(min+x);
*blue=QuantumRange*(min+c);
break;
}
case 4:
{
*red=QuantumRange*(min+x);
*green=QuantumRange*min;
*blue=QuantumRange*(min+c);
break;
}
case 5:
{
*red=QuantumRange*(min+c);
*green=QuantumRange*min;
*blue=QuantumRange*(min+x);
break;
}
default:
{
*red=0.0;
*green=0.0;
*blue=0.0;
}
}
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t H W B T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
% blue) triple.
%
% The format of the ConvertHWBToRGBImage method is:
%
% void ConvertHWBToRGB(const double hue,const double whiteness,
% const double blackness,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o hue, whiteness, blackness: A double value representing a
% component of the HWB color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
const double blackness,double *red,double *green,double *blue)
{
double
b,
f,
g,
n,
r,
v;
ssize_t
i;
/*
Convert HWB to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
v=1.0-blackness;
if (fabs(hue-(-1.0)) < MagickEpsilon)
{
*red=QuantumRange*v;
*green=QuantumRange*v;
*blue=QuantumRange*v;
return;
}
i=CastDoubleToLong(floor(6.0*hue));
f=6.0*hue-i;
if ((i & 0x01) != 0)
f=1.0-f;
n=whiteness+f*(v-whiteness); /* linear interpolation */
switch (i)
{
default:
case 6:
case 0: r=v; g=n; b=whiteness; break;
case 1: r=n; g=v; b=whiteness; break;
case 2: r=whiteness; g=v; b=n; break;
case 3: r=whiteness; g=n; b=v; break;
case 4: r=n; g=whiteness; b=v; break;
case 5: r=v; g=whiteness; b=n; break;
}
*red=QuantumRange*r;
*green=QuantumRange*g;
*blue=QuantumRange*b;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t L C H a b T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
% blue) triple.
%
% The format of the ConvertLCHabToRGBImage method is:
%
% void ConvertLCHabToRGB(const double luma,const double chroma,
% const double hue,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o luma, chroma, hue: A double value representing a component of the
% LCHab color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
const double hue,const IlluminantType illuminant,double *X,double *Y,
double *Z)
{
ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
sin(hue*MagickPI/180.0),illuminant,X,Y,Z);
}
MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
const double hue,const IlluminantType illuminant,double *red,double *green,
double *blue)
{
double
X,
Y,
Z;
/*
Convert LCHab to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,illuminant,
&X,&Y,&Z);
ConvertXYZToRGB(X,Y,Z,red,green,blue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t L C H u v T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
% blue) triple.
%
% The format of the ConvertLCHuvToRGBImage method is:
%
% void ConvertLCHuvToRGB(const double luma,const double chroma,
% const double hue,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
% o luma, chroma, hue: A double value representing a component of the
% LCHuv color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
const double hue,const IlluminantType illuminant,double *X,double *Y,
double *Z)
{
ConvertLuvToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
sin(hue*MagickPI/180.0),illuminant,X,Y,Z);
}
MagickPrivate void ConvertLCHuvToRGB(const double luma,const double chroma,
const double hue,const IlluminantType illuminant,double *red,double *green,
double *blue)
{
double
X,
Y,
Z;
/*
Convert LCHuv to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,illuminant,
&X,&Y,&Z);
ConvertXYZToRGB(X,Y,Z,red,green,blue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H C L %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHCL() transforms a (red, green, blue) to a (hue, chroma,
% luma) triple.
%
% The format of the ConvertRGBToHCL method is:
%
% void ConvertRGBToHCL(const double red,const double green,
% const double blue,double *hue,double *chroma,double *luma)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o hue, chroma, luma: A pointer to a double value representing a
% component of the HCL color space.
%
*/
MagickPrivate void ConvertRGBToHCL(const double red,const double green,
const double blue,double *hue,double *chroma,double *luma)
{
double
c,
h,
max;
/*
Convert RGB to HCL colorspace.
*/
assert(hue != (double *) NULL);
assert(chroma != (double *) NULL);
assert(luma != (double *) NULL);
max=MagickMax(red,MagickMax(green,blue));
c=max-(double) MagickMin(red,MagickMin(green,blue));
h=0.0;
if (fabs(c) < MagickEpsilon)
h=0.0;
else
if (fabs(red-max) < MagickEpsilon)
h=fmod((green-blue)/c+6.0,6.0);
else
if (fabs(green-max) < MagickEpsilon)
h=((blue-red)/c)+2.0;
else
if (fabs(blue-max) < MagickEpsilon)
h=((red-green)/c)+4.0;
*hue=(h/6.0);
*chroma=QuantumScale*c;
*luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H C L p %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
% luma) triple.
%
% The format of the ConvertRGBToHCLp method is:
%
% void ConvertRGBToHCLp(const double red,const double green,
% const double blue,double *hue,double *chroma,double *luma)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o hue, chroma, luma: A pointer to a double value representing a
% component of the HCL color space.
%
*/
MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
const double blue,double *hue,double *chroma,double *luma)
{
double
c,
h,
max;
/*
Convert RGB to HCL colorspace.
*/
assert(hue != (double *) NULL);
assert(chroma != (double *) NULL);
assert(luma != (double *) NULL);
max=MagickMax(red,MagickMax(green,blue));
c=max-MagickMin(red,MagickMin(green,blue));
h=0.0;
if (fabs(c) < MagickEpsilon)
h=0.0;
else
if (fabs(red-max) < MagickEpsilon)
h=fmod((green-blue)/c+6.0,6.0);
else
if (fabs(green-max) < MagickEpsilon)
h=((blue-red)/c)+2.0;
else
if (fabs(blue-max) < MagickEpsilon)
h=((red-green)/c)+4.0;
*hue=(h/6.0);
*chroma=QuantumScale*c;
*luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H S B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
% brightness) triple.
%
% The format of the ConvertRGBToHSB method is:
%
% void ConvertRGBToHSB(const double red,const double green,
% const double blue,double *hue,double *saturation,double *brightness)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel..
%
% o hue, saturation, brightness: A pointer to a double value representing a
% component of the HSB color space.
%
*/
MagickPrivate void ConvertRGBToHSB(const double red,const double green,
const double blue,double *hue,double *saturation,double *brightness)
{
double
delta,
max,
min;
/*
Convert RGB to HSB colorspace.
*/
assert(hue != (double *) NULL);
assert(saturation != (double *) NULL);
assert(brightness != (double *) NULL);
*hue=0.0;
*saturation=0.0;
*brightness=0.0;
min=red < green ? red : green;
if (blue < min)
min=blue;
max=red > green ? red : green;
if (blue > max)
max=blue;
if (fabs(max) < MagickEpsilon)
return;
delta=max-min;
*saturation=delta/max;
*brightness=QuantumScale*max;
if (fabs(delta) < MagickEpsilon)
return;
if (fabs(red-max) < MagickEpsilon)
*hue=(green-blue)/delta;
else
if (fabs(green-max) < MagickEpsilon)
*hue=2.0+(blue-red)/delta;
else
*hue=4.0+(red-green)/delta;
*hue/=6.0;
if (*hue < 0.0)
*hue+=1.0;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H S I %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
% intensity) triple.
%
% The format of the ConvertRGBToHSI method is:
%
% void ConvertRGBToHSI(const double red,const double green,
% const double blue,double *hue,double *saturation,double *intensity)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel..
%
% o hue, saturation, intensity: A pointer to a double value representing a
% component of the HSI color space.
%
*/
MagickPrivate void ConvertRGBToHSI(const double red,const double green,
const double blue,double *hue,double *saturation,double *intensity)
{
double
alpha,
beta;
/*
Convert RGB to HSI colorspace.
*/
assert(hue != (double *) NULL);
assert(saturation != (double *) NULL);
assert(intensity != (double *) NULL);
*intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
if (*intensity <= 0.0)
{
*hue=0.0;
*saturation=0.0;
return;
}
*saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
QuantumScale*blue))/(*intensity);
alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
*hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
if (*hue < 0.0)
*hue+=1.0;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H S L %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
% lightness) triple.
%
% The format of the ConvertRGBToHSL method is:
%
% void ConvertRGBToHSL(const double red,const double green,
% const double blue,double *hue,double *saturation,double *lightness)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel..
%
% o hue, saturation, lightness: A pointer to a double value representing a
% component of the HSL color space.
%
*/
MagickExport void ConvertRGBToHSL(const double red,const double green,
const double blue,double *hue,double *saturation,double *lightness)
{
double
c,
max,
min;
/*
Convert RGB to HSL colorspace.
*/
assert(hue != (double *) NULL);
assert(saturation != (double *) NULL);
assert(lightness != (double *) NULL);
max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
QuantumScale*blue));
min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
QuantumScale*blue));
c=max-min;
*lightness=(max+min)/2.0;
if (c <= 0.0)
{
*hue=0.0;
*saturation=0.0;
return;
}
if (fabs(max-QuantumScale*red) < MagickEpsilon)
{
*hue=(QuantumScale*green-QuantumScale*blue)/c;
if ((QuantumScale*green) < (QuantumScale*blue))
*hue+=6.0;
}
else
if (fabs(max-QuantumScale*green) < MagickEpsilon)
*hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
else
*hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
*hue*=60.0/360.0;
if (*lightness <= 0.5)
*saturation=c*PerceptibleReciprocal(2.0*(*lightness));
else
*saturation=c*PerceptibleReciprocal(2.0-2.0*(*lightness));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H S V %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
% value) triple.
%
% The format of the ConvertRGBToHSV method is:
%
% void ConvertRGBToHSV(const double red,const double green,
% const double blue,double *hue,double *saturation,double *value)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel..
%
% o hue, saturation, value: A pointer to a double value representing a
% component of the HSV color space.
%
*/
MagickPrivate void ConvertRGBToHSV(const double red,const double green,
const double blue,double *hue,double *saturation,double *value)
{
double
c,
max,
min;
/*
Convert RGB to HSV colorspace.
*/
assert(hue != (double *) NULL);
assert(saturation != (double *) NULL);
assert(value != (double *) NULL);
max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
QuantumScale*blue));
min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
QuantumScale*blue));
c=max-min;
*value=max;
if (c <= 0.0)
{
*hue=0.0;
*saturation=0.0;
return;
}
if (fabs(max-QuantumScale*red) < MagickEpsilon)
{
*hue=(QuantumScale*green-QuantumScale*blue)/c;
if ((QuantumScale*green) < (QuantumScale*blue))
*hue+=6.0;
}
else
if (fabs(max-QuantumScale*green) < MagickEpsilon)
*hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
else
*hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
*hue*=60.0/360.0;
*saturation=c*PerceptibleReciprocal(max);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o H W B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
% blackness) triple.
%
% The format of the ConvertRGBToHWB method is:
%
% void ConvertRGBToHWB(const double red,const double green,
% const double blue,double *hue,double *whiteness,double *blackness)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o hue, whiteness, blackness: A pointer to a double value representing a
% component of the HWB color space.
%
*/
MagickPrivate void ConvertRGBToHWB(const double red,const double green,
const double blue,double *hue,double *whiteness,double *blackness)
{
double
f,
p,
v,
w;
/*
Convert RGB to HWB colorspace.
*/
assert(hue != (double *) NULL);
assert(whiteness != (double *) NULL);
assert(blackness != (double *) NULL);
w=MagickMin(red,MagickMin(green,blue));
v=MagickMax(red,MagickMax(green,blue));
*blackness=1.0-QuantumScale*v;
*whiteness=QuantumScale*w;
if (fabs(v-w) < MagickEpsilon)
{
*hue=(-1.0);
return;
}
f=(fabs(red-w) < MagickEpsilon) ? green-blue :
((fabs(green-w) < MagickEpsilon) ? blue-red : red-green);
p=(fabs(red-w) < MagickEpsilon) ? 3.0 :
((fabs(green-w) < MagickEpsilon) ? 5.0 : 1.0);
*hue=(p-f/(v-1.0*w))/6.0;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o L a b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToLab() transforms a (red, green, blue) to a (L, a, b) triple.
%
% The format of the ConvertRGBToLCHab method is:
%
% void ConvertRGBToLCHab(const double red,const double green,
% const double blue,double *L,double *a,double *b)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o L, a, b: A pointer to a double value representing a component of the
% Lab color space.
%
*/
MagickPrivate void ConvertRGBToLab(const double red,const double green,
const double blue,const IlluminantType illuminant,double *L,double *a,
double *b)
{
double
X,
Y,
Z;
ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
ConvertXYZToLab(X,Y,Z,illuminant,L,a,b);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o L C H a b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
% hue) triple.
%
% The format of the ConvertRGBToLCHab method is:
%
% void ConvertRGBToLCHab(const double red,const double green,
% const double blue,double *luma,double *chroma,double *hue)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o luma, chroma, hue: A pointer to a double value representing a
% component of the LCH color space.
%
*/
static inline void ConvertXYZToLCHab(const double X,const double Y,
const double Z,const IlluminantType illuminant,double *luma,double *chroma,
double *hue)
{
double
a,
b;
ConvertXYZToLab(X,Y,Z,illuminant,luma,&a,&b);
*chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
*hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0;
if (*hue < 0.0)
*hue+=1.0;
}
MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
const double blue,const IlluminantType illuminant,double *luma,double *chroma,
double *hue)
{
double
X,
Y,
Z;
/*
Convert RGB to LCHab colorspace.
*/
assert(luma != (double *) NULL);
assert(chroma != (double *) NULL);
assert(hue != (double *) NULL);
ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
ConvertXYZToLCHab(X,Y,Z,illuminant,luma,chroma,hue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o n v e r t R G B T o L C H u v %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
% hue) triple.
%
% The format of the ConvertRGBToLCHuv method is:
%
% void ConvertRGBToLCHuv(const double red,const double green,
% const double blue,double *luma,double *chroma,double *hue)
%
% A description of each parameter follows:
%
% o red, green, blue: A Quantum value representing the red, green, and
% blue component of a pixel.
%
% o luma, chroma, hue: A pointer to a double value representing a
% component of the LCHuv color space.
%
*/
static inline void ConvertXYZToLCHuv(const double X,const double Y,
const double Z,const IlluminantType illuminant,double *luma,double *chroma,
double *hue)
{
double
u,
v;
ConvertXYZToLuv(X,Y,Z,illuminant,luma,&u,&v);
*chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
*hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
if (*hue < 0.0)
*hue+=1.0;
}
MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
const double blue,const IlluminantType illuminant,double *luma,double *chroma,
double *hue)
{
double
X,
Y,
Z;
/*
Convert RGB to LCHuv colorspace.
*/
assert(luma != (double *) NULL);
assert(chroma != (double *) NULL);
assert(hue != (double *) NULL);
ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
ConvertXYZToLCHuv(X,Y,Z,illuminant,luma,chroma,hue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% E x p a n d A f f i n e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ExpandAffine() computes the affine's expansion factor, i.e. the square root
% of the factor by which the affine transform affects area. In an affine
% transform composed of scaling, rotation, shearing, and translation, returns
% the amount of scaling.
%
% The format of the ExpandAffine method is:
%
% double ExpandAffine(const AffineMatrix *affine)
%
% A description of each parameter follows:
%
% o expansion: ExpandAffine returns the affine's expansion factor.
%
% o affine: A pointer the affine transform of type AffineMatrix.
%
*/
MagickExport double ExpandAffine(const AffineMatrix *affine)
{
assert(affine != (const AffineMatrix *) NULL);
return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e n e r a t e D i f f e r e n t i a l N o i s e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GenerateDifferentialNoise() generates differentual noise.
%
% The format of the GenerateDifferentialNoise method is:
%
% double GenerateDifferentialNoise(RandomInfo *random_info,
% const Quantum pixel,const NoiseType noise_type,const double attenuate)
%
% A description of each parameter follows:
%
% o random_info: the random info.
%
% o pixel: noise is relative to this pixel value.
%
% o noise_type: the type of noise.
%
% o attenuate: attenuate the noise.
%
*/
MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
const Quantum pixel,const NoiseType noise_type,const double attenuate)
{
#define SigmaUniform (attenuate*0.015625)
#define SigmaGaussian (attenuate*0.015625)
#define SigmaImpulse (attenuate*0.1)
#define SigmaLaplacian (attenuate*0.0390625)
#define SigmaMultiplicativeGaussian (attenuate*0.5)
#define SigmaPoisson (attenuate*12.5)
#define SigmaRandom (attenuate)
#define TauGaussian (attenuate*0.078125)
double
alpha,
beta,
noise,
sigma;
alpha=GetPseudoRandomValue(random_info);
switch (noise_type)
{
case UniformNoise:
default:
{
noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
break;
}
case GaussianNoise:
{
double
gamma,
tau;
if (fabs(alpha) < MagickEpsilon)
alpha=1.0;
beta=GetPseudoRandomValue(random_info);
gamma=sqrt(-2.0*log(alpha));
sigma=gamma*cos((double) (2.0*MagickPI*beta));
tau=gamma*sin((double) (2.0*MagickPI*beta));
noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
QuantumRange*TauGaussian*tau);
break;
}
case ImpulseNoise:
{
if (alpha < (SigmaImpulse/2.0))
noise=0.0;
else
if (alpha >= (1.0-(SigmaImpulse/2.0)))
noise=(double) QuantumRange;
else
noise=(double) pixel;
break;
}
case LaplacianNoise:
{
if (alpha <= 0.5)
{
if (alpha <= MagickEpsilon)
noise=(double) (pixel-QuantumRange);
else
noise=(double) (pixel+QuantumRange*SigmaLaplacian*log(2.0*alpha)+
0.5);
break;
}
beta=1.0-alpha;
if (beta <= (0.5*MagickEpsilon))
noise=(double) (pixel+QuantumRange);
else
noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
break;
}
case MultiplicativeGaussianNoise:
{
sigma=1.0;
if (alpha > MagickEpsilon)
sigma=sqrt(-2.0*log(alpha));
beta=GetPseudoRandomValue(random_info);
noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
cos((double) (2.0*MagickPI*beta))/2.0);
break;
}
case PoissonNoise:
{
double
poisson;
ssize_t
i;
poisson=exp(-SigmaPoisson*QuantumScale*pixel);
for (i=0; alpha > poisson; i++)
{
beta=GetPseudoRandomValue(random_info);
alpha*=beta;
}
noise=(double) (QuantumRange*i*PerceptibleReciprocal(SigmaPoisson));
break;
}
case RandomNoise:
{
noise=(double) (QuantumRange*SigmaRandom*alpha);
break;
}
}
return(noise);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t O p t i m a l K e r n e l W i d t h %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
% filter. Start with the minimum value of 3 pixels and walk out until we drop
% below the threshold of one pixel numerical accuracy.
%
% The format of the GetOptimalKernelWidth method is:
%
% size_t GetOptimalKernelWidth(const double radius,
% const double sigma)
%
% A description of each parameter follows:
%
% o width: GetOptimalKernelWidth returns the optimal width of a
% convolution kernel.
%
% o radius: the radius of the Gaussian, in pixels, not counting the center
% pixel.
%
% o sigma: the standard deviation of the Gaussian, in pixels.
%
*/
MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
const double sigma)
{
double
alpha,
beta,
gamma,
normalize,
value;
ssize_t
i;
size_t
width;
ssize_t
j;
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
if (radius > MagickEpsilon)
return((size_t) (2.0*ceil(radius)+1.0));
gamma=fabs(sigma);
if (gamma <= MagickEpsilon)
return(3UL);
alpha=PerceptibleReciprocal(2.0*gamma*gamma);
beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
for (width=5; ; )
{
normalize=0.0;
j=(ssize_t) (width-1)/2;
for (i=(-j); i <= j; i++)
normalize+=exp(-((double) (i*i))*alpha)*beta;
value=exp(-((double) (j*j))*alpha)*beta/normalize;
if ((value < QuantumScale) || (value < MagickEpsilon))
break;
width+=2;
}
return((size_t) (width-2));
}
MagickPrivate size_t GetOptimalKernelWidth2D(const double radius,
const double sigma)
{
double
alpha,
beta,
gamma,
normalize,
value;
size_t
width;
ssize_t
j,
u,
v;
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
if (radius > MagickEpsilon)
return((size_t) (2.0*ceil(radius)+1.0));
gamma=fabs(sigma);
if (gamma <= MagickEpsilon)
return(3UL);
alpha=PerceptibleReciprocal(2.0*gamma*gamma);
beta=(double) PerceptibleReciprocal((double) Magick2PI*gamma*gamma);
for (width=5; ; )
{
normalize=0.0;
j=(ssize_t) (width-1)/2;
for (v=(-j); v <= j; v++)
for (u=(-j); u <= j; u++)
normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
value=exp(-((double) (j*j))*alpha)*beta/normalize;
if ((value < QuantumScale) || (value < MagickEpsilon))
break;
width+=2;
}
return((size_t) (width-2));
}
MagickPrivate size_t GetOptimalKernelWidth(const double radius,
const double sigma)
{
return(GetOptimalKernelWidth1D(radius,sigma));
}