43#include "magick/studio.h"
44#include "magick/color-private.h"
45#include "magick/draw.h"
46#include "magick/gem.h"
47#include "magick/gem-private.h"
48#include "magick/image.h"
49#include "magick/image-private.h"
50#include "magick/log.h"
51#include "magick/memory_.h"
52#include "magick/pixel-private.h"
53#include "magick/quantum.h"
54#include "magick/random_.h"
55#include "magick/resize.h"
56#include "magick/transform.h"
57#include "magick/signature-private.h"
86MagickExport
void ConvertHCLToRGB(
const double hue,
const double chroma,
87 const double luma,Quantum *red,Quantum *green,Quantum *blue)
101 assert(red != (Quantum *) NULL);
102 assert(green != (Quantum *) NULL);
103 assert(blue != (Quantum *) NULL);
106 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
110 if ((0.0 <= h) && (h < 1.0))
116 if ((1.0 <= h) && (h < 2.0))
122 if ((2.0 <= h) && (h < 3.0))
128 if ((3.0 <= h) && (h < 4.0))
134 if ((4.0 <= h) && (h < 5.0))
140 if ((5.0 <= h) && (h < 6.0))
145 m=luma-(0.298839*r+0.586811*g+0.114350*b);
146 *red=ClampToQuantum((MagickRealType) QuantumRange*(r+m));
147 *green=ClampToQuantum((MagickRealType) QuantumRange*(g+m));
148 *blue=ClampToQuantum((MagickRealType) QuantumRange*(b+m));
179MagickExport
void ConvertHCLpToRGB(
const double hue,
const double chroma,
180 const double luma,Quantum *red,Quantum *green,Quantum *blue)
195 assert(red != (Quantum *) NULL);
196 assert(green != (Quantum *) NULL);
197 assert(blue != (Quantum *) NULL);
200 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
204 if ((0.0 <= h) && (h < 1.0))
210 if ((1.0 <= h) && (h < 2.0))
216 if ((2.0 <= h) && (h < 3.0))
222 if ((3.0 <= h) && (h < 4.0))
228 if ((4.0 <= h) && (h < 5.0))
234 if ((5.0 <= h) && (h < 6.0))
239 m=luma-(0.298839*r+0.586811*g+0.114350*b);
249 z=(1.0-luma)/(m+c-luma);
252 *red=ClampToQuantum((MagickRealType) QuantumRange*(z*r+m));
253 *green=ClampToQuantum((MagickRealType) QuantumRange*(z*g+m));
254 *blue=ClampToQuantum((MagickRealType) QuantumRange*(z*b+m));
284MagickExport
void ConvertHSBToRGB(
const double hue,
const double saturation,
285 const double brightness,Quantum *red,Quantum *green,Quantum *blue)
297 assert(red != (Quantum *) NULL);
298 assert(green != (Quantum *) NULL);
299 assert(blue != (Quantum *) NULL);
300 if (fabs(saturation) < MagickEpsilon)
302 *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
307 h=6.0*(hue-floor(hue));
308 f=h-floor((
double) h);
309 p=brightness*(1.0-saturation);
310 q=brightness*(1.0-saturation*f);
311 t=brightness*(1.0-(saturation*(1.0-f)));
317 *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
318 *green=ClampToQuantum((MagickRealType) QuantumRange*t);
319 *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
324 *red=ClampToQuantum((MagickRealType) QuantumRange*q);
325 *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
326 *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
331 *red=ClampToQuantum((MagickRealType) QuantumRange*p);
332 *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
333 *blue=ClampToQuantum((MagickRealType) QuantumRange*t);
338 *red=ClampToQuantum((MagickRealType) QuantumRange*p);
339 *green=ClampToQuantum((MagickRealType) QuantumRange*q);
340 *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
345 *red=ClampToQuantum((MagickRealType) QuantumRange*t);
346 *green=ClampToQuantum((MagickRealType) QuantumRange*p);
347 *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
352 *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
353 *green=ClampToQuantum((MagickRealType) QuantumRange*p);
354 *blue=ClampToQuantum((MagickRealType) QuantumRange*q);
387MagickExport
void ConvertHSIToRGB(
const double hue,
const double saturation,
388 const double intensity,Quantum *red,Quantum *green,Quantum *blue)
399 assert(red != (Quantum *) NULL);
400 assert(green != (Quantum *) NULL);
401 assert(blue != (Quantum *) NULL);
403 h-=360.0*floor(h/360.0);
406 b=intensity*(1.0-saturation);
407 r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
415 r=intensity*(1.0-saturation);
416 g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
423 g=intensity*(1.0-saturation);
424 b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
428 *red=ClampToQuantum((MagickRealType) QuantumRange*r);
429 *green=ClampToQuantum((MagickRealType) QuantumRange*g);
430 *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
460MagickExport
void ConvertHSLToRGB(
const double hue,
const double saturation,
461 const double lightness,Quantum *red,Quantum *green,Quantum *blue)
475 assert(red != (Quantum *) NULL);
476 assert(green != (Quantum *) NULL);
477 assert(blue != (Quantum *) NULL);
479 if (lightness <= 0.5)
480 c=2.0*lightness*saturation;
482 c=(2.0-2.0*lightness)*saturation;
484 h-=360.0*floor(h/360.0);
486 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
487 switch ((
int) floor(h))
533 *red=ClampToQuantum((MagickRealType) QuantumRange*r);
534 *green=ClampToQuantum((MagickRealType) QuantumRange*g);
535 *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
565MagickExport
void ConvertHSVToRGB(
const double hue,
const double saturation,
566 const double value,Quantum *red,Quantum *green,Quantum *blue)
580 assert(red != (Quantum *) NULL);
581 assert(green != (Quantum *) NULL);
582 assert(blue != (Quantum *) NULL);
586 h-=360.0*floor(h/360.0);
588 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
589 switch ((
int) floor(h))
635 *red=ClampToQuantum((MagickRealType) QuantumRange*r);
636 *green=ClampToQuantum((MagickRealType) QuantumRange*g);
637 *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
667MagickExport
void ConvertHWBToRGB(
const double hue,
const double whiteness,
668 const double blackness,Quantum *red,Quantum *green,Quantum *blue)
684 assert(red != (Quantum *) NULL);
685 assert(green != (Quantum *) NULL);
686 assert(blue != (Quantum *) NULL);
688 if (fabs(hue-(-1.0)) < MagickEpsilon)
690 *red=ClampToQuantum((MagickRealType) QuantumRange*v);
691 *green=ClampToQuantum((MagickRealType) QuantumRange*v);
692 *blue=ClampToQuantum((MagickRealType) QuantumRange*v);
695 i=CastDoubleToLong(floor(6.0*hue));
699 n=whiteness+f*(v-whiteness);
703 default: r=v; g=n; b=whiteness;
break;
704 case 1: r=n; g=v; b=whiteness;
break;
705 case 2: r=whiteness; g=v; b=n;
break;
706 case 3: r=whiteness; g=n; b=v;
break;
707 case 4: r=n; g=whiteness; b=v;
break;
708 case 5: r=v; g=whiteness; b=n;
break;
710 *red=ClampToQuantum((MagickRealType) QuantumRange*r);
711 *green=ClampToQuantum((MagickRealType) QuantumRange*g);
712 *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
743static inline void ConvertLCHabToXYZ(
const double luma,
const double chroma,
744 const double hue,
double *X,
double *Y,
double *Z)
746 ConvertLabToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
747 sin(DegreesToRadians(hue)),X,Y,Z);
750MagickExport
void ConvertLCHabToRGB(
const double luma,
const double chroma,
751 const double hue,Quantum *red,Quantum *green,Quantum *blue)
761 assert(red != (Quantum *) NULL);
762 assert(green != (Quantum *) NULL);
763 assert(blue != (Quantum *) NULL);
764 ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
765 ConvertXYZToRGB(X,Y,Z,red,green,blue);
796static inline void ConvertLCHuvToXYZ(
const double luma,
const double chroma,
797 const double hue,
double *X,
double *Y,
double *Z)
799 ConvertLuvToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
800 sin(DegreesToRadians(hue)),X,Y,Z);
803MagickExport
void ConvertLCHuvToRGB(
const double luma,
const double chroma,
804 const double hue,Quantum *red,Quantum *green,Quantum *blue)
814 assert(red != (Quantum *) NULL);
815 assert(green != (Quantum *) NULL);
816 assert(blue != (Quantum *) NULL);
817 ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
818 ConvertXYZToRGB(X,Y,Z,red,green,blue);
849MagickExport
void ConvertRGBToHCL(
const Quantum red,
const Quantum green,
850 const Quantum blue,
double *hue,
double *chroma,
double *luma)
863 assert(hue != (
double *) NULL);
864 assert(chroma != (
double *) NULL);
865 assert(luma != (
double *) NULL);
869 max=MagickMax(r,MagickMax(g,b));
870 c=max-(double) MagickMin(r,MagickMin(g,b));
872 if (fabs(c) < MagickEpsilon)
875 if (red == (Quantum) max)
876 h=fmod((g-b)/c+6.0,6.0);
878 if (green == (Quantum) max)
881 if (blue == (Quantum) max)
884 *chroma=QuantumScale*c;
885 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
916MagickExport
void ConvertRGBToHCLp(
const Quantum red,
const Quantum green,
917 const Quantum blue,
double *hue,
double *chroma,
double *luma)
930 assert(hue != (
double *) NULL);
931 assert(chroma != (
double *) NULL);
932 assert(luma != (
double *) NULL);
936 max=MagickMax(r,MagickMax(g,b));
937 c=max-(double) MagickMin(r,MagickMin(g,b));
939 if (fabs(c) < MagickEpsilon)
942 if (red == (Quantum) max)
943 h=fmod((g-b)/c+6.0,6.0);
945 if (green == (Quantum) max)
948 if (blue == (Quantum) max)
951 *chroma=QuantumScale*c;
952 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
983MagickExport
void ConvertRGBToHSB(
const Quantum red,
const Quantum green,
984 const Quantum blue,
double *hue,
double *saturation,
double *brightness)
997 assert(hue != (
double *) NULL);
998 assert(saturation != (
double *) NULL);
999 assert(brightness != (
double *) NULL);
1012 if (fabs(max) < MagickEpsilon)
1015 *saturation=delta/max;
1016 *brightness=QuantumScale*max;
1017 if (fabs(delta) < MagickEpsilon)
1019 if (fabs(r-max) < MagickEpsilon)
1022 if (fabs(g-max) < MagickEpsilon)
1023 *hue=2.0+(b-r)/delta;
1025 *hue=4.0+(r-g)/delta;
1059MagickExport
void ConvertRGBToHSI(
const Quantum red,
const Quantum green,
1060 const Quantum blue,
double *hue,
double *saturation,
double *intensity)
1069 assert(hue != (
double *) NULL);
1070 assert(saturation != (
double *) NULL);
1071 assert(intensity != (
double *) NULL);
1072 *intensity=(QuantumScale*(double) red+QuantumScale*(double) green+
1073 QuantumScale*(double) blue)/3.0;
1074 if (*intensity <= 0.0)
1080 *saturation=1.0-MagickMin(QuantumScale*(
double) red,MagickMin(QuantumScale*
1081 (
double) green,QuantumScale*(
double) blue))/(*intensity);
1082 alpha=0.5*(2.0*QuantumScale*(double) red-QuantumScale*(double) green-
1083 QuantumScale*(double) blue);
1084 beta=0.8660254037844385*(QuantumScale*(double) green-QuantumScale*(double)
1086 *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
1119MagickExport
void ConvertRGBToHSL(
const Quantum red,
const Quantum green,
1120 const Quantum blue,
double *hue,
double *saturation,
double *lightness)
1130 assert(hue != (
double *) NULL);
1131 assert(saturation != (
double *) NULL);
1132 assert(lightness != (
double *) NULL);
1133 max=MagickMax(QuantumScale*(
double) red,MagickMax(QuantumScale*(
double) green,
1134 QuantumScale*(
double) blue));
1135 min=MagickMin(QuantumScale*(
double) red,MagickMin(QuantumScale*(
double) green,
1136 QuantumScale*(
double) blue));
1138 *lightness=(max+min)/2.0;
1145 if (fabs(max-QuantumScale*(
double) red) < MagickEpsilon)
1147 *hue=(QuantumScale*(double) green-QuantumScale*(double) blue)/c;
1148 if ((QuantumScale*(
double) green) < (QuantumScale*(
double) blue))
1152 if (fabs(max-QuantumScale*(
double) green) < MagickEpsilon)
1153 *hue=2.0+(QuantumScale*(double) blue-QuantumScale*(double) red)/c;
1155 *hue=4.0+(QuantumScale*(double) red-QuantumScale*(double) green)/c;
1157 if (*lightness <= 0.5)
1158 *saturation=c*PerceptibleReciprocal(2.0*(*lightness));
1160 *saturation=c*PerceptibleReciprocal(2.0-2.0*(*lightness));
1191MagickExport
void ConvertRGBToHSV(
const Quantum red,
const Quantum green,
1192 const Quantum blue,
double *hue,
double *saturation,
double *value)
1202 assert(hue != (
double *) NULL);
1203 assert(saturation != (
double *) NULL);
1204 assert(value != (
double *) NULL);
1205 max=MagickMax(QuantumScale*(
double) red,MagickMax(QuantumScale*(
double) green,
1206 QuantumScale*(
double) blue));
1207 min=MagickMin(QuantumScale*(
double) red,MagickMin(QuantumScale*(
double) green,
1208 QuantumScale*(
double) blue));
1217 if (fabs(max-QuantumScale*(
double) red) < MagickEpsilon)
1219 *hue=(QuantumScale*(double) green-QuantumScale*(double) blue)/c;
1220 if ((QuantumScale*(
double) green) < (QuantumScale*(
double) blue))
1224 if (fabs(max-QuantumScale*(
double) green) < MagickEpsilon)
1225 *hue=2.0+(QuantumScale*(double) blue-QuantumScale*(double) red)/c;
1227 *hue=4.0+(QuantumScale*(double) red-QuantumScale*(double) green)/c;
1229 *saturation=c*PerceptibleReciprocal(max);
1260MagickExport
void ConvertRGBToHWB(
const Quantum red,
const Quantum green,
1261 const Quantum blue,
double *hue,
double *whiteness,
double *blackness)
1275 assert(hue != (
double *) NULL);
1276 assert(whiteness != (
double *) NULL);
1277 assert(blackness != (
double *) NULL);
1281 w=MagickMin(r,MagickMin(g,b));
1282 v=MagickMax(r,MagickMax(g,b));
1283 *blackness=1.0-QuantumScale*v;
1284 *whiteness=QuantumScale*w;
1285 if (fabs(v-w) < MagickEpsilon)
1290 f=(fabs(r-w) < MagickEpsilon) ? g-b : ((fabs(g-w) < MagickEpsilon) ? b-r :
1292 p=(fabs(r-w) < MagickEpsilon) ? 3.0 : ((fabs(g-w) < MagickEpsilon) ? 5.0 :
1294 *hue=(p-f/(v-1.0*w))/6.0;
1325static inline void ConvertXYZToLCHab(
const double X,
const double Y,
1326 const double Z,
double *luma,
double *chroma,
double *hue)
1332 ConvertXYZToLab(X,Y,Z,luma,&a,&b);
1333 *chroma=hypot(a-0.5,b-0.5)/255.0+0.5;
1334 *hue=180.0*atan2(b-0.5,a-0.5)/MagickPI/360.0;
1339MagickExport
void ConvertRGBToLCHab(
const Quantum red,
const Quantum green,
1340 const Quantum blue,
double *luma,
double *chroma,
double *hue)
1350 assert(luma != (
double *) NULL);
1351 assert(chroma != (
double *) NULL);
1352 assert(hue != (
double *) NULL);
1353 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1354 ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
1386static inline void ConvertXYZToLCHuv(
const double X,
const double Y,
1387 const double Z,
double *luma,
double *chroma,
double *hue)
1393 ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
1394 *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
1395 *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
1400MagickExport
void ConvertRGBToLCHuv(
const Quantum red,
const Quantum green,
1401 const Quantum blue,
double *luma,
double *chroma,
double *hue)
1411 assert(luma != (
double *) NULL);
1412 assert(chroma != (
double *) NULL);
1413 assert(hue != (
double *) NULL);
1414 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1415 ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
1445MagickExport
double ExpandAffine(
const AffineMatrix *affine)
1448 return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
1481MagickExport
double GenerateDifferentialNoise(
RandomInfo *random_info,
1482 const Quantum pixel,
const NoiseType noise_type,
const MagickRealType attenuate)
1484#define SigmaUniform (attenuate*0.015625)
1485#define SigmaGaussian (attenuate*0.015625)
1486#define SigmaImpulse (attenuate*0.1)
1487#define SigmaLaplacian (attenuate*0.0390625)
1488#define SigmaMultiplicativeGaussian (attenuate*0.5)
1489#define SigmaPoisson (attenuate*12.5)
1490#define SigmaRandom (attenuate)
1491#define TauGaussian (attenuate*0.078125)
1499 alpha=GetPseudoRandomValue(random_info);
1505 noise=(double) pixel+(
double) QuantumRange*SigmaUniform*(alpha-0.5);
1514 if (fabs(alpha) < MagickEpsilon)
1516 beta=GetPseudoRandomValue(random_info);
1517 gamma=sqrt(-2.0*log(alpha));
1518 sigma=gamma*cos((
double) (2.0*MagickPI*beta));
1519 tau=gamma*sin((
double) (2.0*MagickPI*beta));
1520 noise=(double) pixel+sqrt((
double) pixel)*SigmaGaussian*sigma+
1521 (double) QuantumRange*TauGaussian*tau;
1526 if (alpha < (SigmaImpulse/2.0))
1529 if (alpha >= (1.0-(SigmaImpulse/2.0)))
1530 noise=(double) QuantumRange;
1532 noise=(double) pixel;
1535 case LaplacianNoise:
1539 if (alpha <= MagickEpsilon)
1540 noise=(double) (pixel-QuantumRange);
1542 noise=(double) pixel+(
double) QuantumRange*SigmaLaplacian*
1547 if (beta <= (0.5*MagickEpsilon))
1548 noise=(double) (pixel+QuantumRange);
1550 noise=(double) pixel-(
double) QuantumRange*SigmaLaplacian*
1554 case MultiplicativeGaussianNoise:
1557 if (alpha > MagickEpsilon)
1558 sigma=sqrt(-2.0*log(alpha));
1559 beta=GetPseudoRandomValue(random_info);
1560 noise=(double) pixel+(
double) pixel*SigmaMultiplicativeGaussian*sigma*
1561 cos((
double) (2.0*MagickPI*beta))/2.0;
1572 poisson=exp(-SigmaPoisson*QuantumScale*(
double) pixel);
1573 for (i=0; alpha > poisson; i++)
1575 beta=GetPseudoRandomValue(random_info);
1578 noise=(double) QuantumRange*i*PerceptibleReciprocal(SigmaPoisson);
1583 noise=(double) QuantumRange*SigmaRandom*alpha;
1617MagickExport
size_t GetOptimalKernelWidth1D(
const double radius,
1634 if (IsEventLogging() != MagickFalse)
1635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
1636 if (radius > MagickEpsilon)
1637 return((
size_t) (2.0*ceil(radius)+1.0));
1639 if (gamma <= MagickEpsilon)
1641 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1642 beta=(double) PerceptibleReciprocal((
double) MagickSQ2PI*gamma);
1646 j=(ssize_t) (width-1)/2;
1647 for (i=(-j); i <= j; i++)
1648 normalize+=exp(-((
double) (i*i))*alpha)*beta;
1649 value=exp(-((
double) (j*j))*alpha)*beta/normalize;
1650 if ((value < QuantumScale) || (value < MagickEpsilon))
1654 return((
size_t) (width-2));
1657MagickExport
size_t GetOptimalKernelWidth2D(
const double radius,
1675 if (IsEventLogging() != MagickFalse)
1676 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
1677 if (radius > MagickEpsilon)
1678 return((
size_t) (2.0*ceil(radius)+1.0));
1680 if (gamma <= MagickEpsilon)
1682 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1683 beta=(double) PerceptibleReciprocal((
double) Magick2PI*gamma*gamma);
1687 j=(ssize_t) (width-1)/2;
1688 for (v=(-j); v <= j; v++)
1689 for (u=(-j); u <= j; u++)
1690 normalize+=exp(-((
double) (u*u+v*v))*alpha)*beta;
1691 value=exp(-((
double) (j*j))*alpha)*beta/normalize;
1692 if ((value < QuantumScale) || (value < MagickEpsilon))
1696 return((
size_t) (width-2));
1699MagickExport
size_t GetOptimalKernelWidth(
const double radius,
1702 return(GetOptimalKernelWidth1D(radius,sigma));