|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% 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));
|
|
|
}
|