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.
381 lines
12 KiB
381 lines
12 KiB
/*
|
|
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.
|
|
|
|
MagickCore private graphic gems methods.
|
|
*/
|
|
#ifndef MAGICKCORE_GEM_PRIVATE_H
|
|
#define MAGICKCORE_GEM_PRIVATE_H
|
|
|
|
#include "MagickCore/pixel-accessor.h"
|
|
#include "MagickCore/visual-effects.h"
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define IlluminantX 0.95047
|
|
#define IlluminantY 1.0
|
|
#define IlluminantZ 1.08883
|
|
#define CIEEpsilon (216.0/24389.0)
|
|
#define CIEK (24389.0/27.0)
|
|
|
|
static const PrimaryInfo
|
|
illuminant_tristimulus[] =
|
|
{
|
|
{ 1.09850, 1.00000, 0.35585 }, /* A */
|
|
{ 0.99072, 1.00000, 0.85223 }, /* B */
|
|
{ 0.98074, 1.00000, 1.18232 }, /* C */
|
|
{ 0.96422, 1.00000, 0.82521 }, /* D50 */
|
|
{ 0.95682, 1.00000, 0.92149 }, /* D55 */
|
|
{ 0.95047, 1.00000, 1.08883 }, /* D65 */
|
|
{ 0.94972, 1.00000, 1.22638 }, /* D75 */
|
|
{ 1.00000, 1.00000, 1.00000 }, /* E */
|
|
{ 0.99186, 1.00000, 0.67393 }, /* F2 */
|
|
{ 0.95041, 1.00000, 1.08747 }, /* F7 */
|
|
{ 1.00962, 1.00000, 0.64350 } /* F11 */
|
|
};
|
|
|
|
extern MagickPrivate double
|
|
GenerateDifferentialNoise(RandomInfo *,const Quantum,const NoiseType,
|
|
const double);
|
|
|
|
extern MagickPrivate size_t
|
|
GetOptimalKernelWidth(const double,const double),
|
|
GetOptimalKernelWidth1D(const double,const double),
|
|
GetOptimalKernelWidth2D(const double,const double);
|
|
|
|
extern MagickPrivate void
|
|
ConvertHCLToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertHCLpToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertHSBToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertHSIToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertHSVToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertHWBToRGB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertLCHabToRGB(const double,const double,const double,const IlluminantType,
|
|
double *,double *,double *),
|
|
ConvertLCHuvToRGB(const double,const double,const double,const IlluminantType,
|
|
double *,double *,double *),
|
|
ConvertRGBToHCL(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToHCLp(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToHSB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToHSI(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToHSV(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToHWB(const double,const double,const double,double *,double *,
|
|
double *),
|
|
ConvertRGBToLab(const double,const double,const double,const IlluminantType,
|
|
double *,double *,double *),
|
|
ConvertRGBToLCHab(const double,const double,const double,const IlluminantType,
|
|
double *,double *,double *),
|
|
ConvertRGBToLCHuv(const double,const double,const double,const IlluminantType,
|
|
double *,double *,double *);
|
|
|
|
static inline void ConvertAdobe98ToXYZ(const double red,const double green,
|
|
const double blue,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
/*
|
|
Convert Adobe '98 to XYZ colorspace.
|
|
*/
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
r=QuantumScale*DecodePixelGamma(red);
|
|
g=QuantumScale*DecodePixelGamma(green);
|
|
b=QuantumScale*DecodePixelGamma(blue);
|
|
*X=0.57666904291013050*r+0.18555823790654630*g+0.18822864623499470*b;
|
|
*Y=0.29734497525053605*r+0.62736356625546610*g+0.07529145849399788*b;
|
|
*Z=0.02703136138641234*r+0.07068885253582723*g+0.99133753683763880*b;
|
|
}
|
|
|
|
static inline void ConvertDisplayP3ToXYZ(const double red,const double green,
|
|
const double blue,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
/*
|
|
Convert Display P3 to XYZ colorspace.
|
|
*/
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
r=QuantumScale*DecodePixelGamma(red);
|
|
g=QuantumScale*DecodePixelGamma(green);
|
|
b=QuantumScale*DecodePixelGamma(blue);
|
|
*X=0.4865709486482162*r+0.26566769316909306*g+0.1982172852343625*b;
|
|
*Y=0.2289745640697488*r+0.69173852183650640*g+0.0792869140937450*b;
|
|
*Z=0.0000000000000000*r+0.04511338185890264*g+1.0439443689009760*b;
|
|
}
|
|
|
|
static inline void ConvertLabToXYZ(const double L,const double a,const double b,
|
|
const IlluminantType illuminant,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
x,
|
|
y,
|
|
z;
|
|
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
y=(L+16.0)/116.0;
|
|
x=y+a/500.0;
|
|
z=y-b/200.0;
|
|
if ((x*x*x) > CIEEpsilon)
|
|
x=(x*x*x);
|
|
else
|
|
x=(116.0*x-16.0)/CIEK;
|
|
if (L > (CIEK*CIEEpsilon))
|
|
y=(y*y*y);
|
|
else
|
|
y=L/CIEK;
|
|
if ((z*z*z) > CIEEpsilon)
|
|
z=(z*z*z);
|
|
else
|
|
z=(116.0*z-16.0)/CIEK;
|
|
*X=illuminant_tristimulus[illuminant].x*x;
|
|
*Y=illuminant_tristimulus[illuminant].y*y;
|
|
*Z=illuminant_tristimulus[illuminant].z*z;
|
|
}
|
|
|
|
static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
|
|
const IlluminantType illuminant,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
gamma;
|
|
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
if (L > (CIEK*CIEEpsilon))
|
|
*Y=(double) pow((L+16.0)/116.0,3.0);
|
|
else
|
|
*Y=L/CIEK;
|
|
gamma=PerceptibleReciprocal((((52.0*L*PerceptibleReciprocal(u+13.0*L*
|
|
(4.0*illuminant_tristimulus[illuminant].x/
|
|
(illuminant_tristimulus[illuminant].x+15.0*
|
|
illuminant_tristimulus[illuminant].y+3.0*
|
|
illuminant_tristimulus[illuminant].z))))-1.0)/3.0)-(-1.0/3.0));
|
|
*X=gamma*((*Y*((39.0*L*PerceptibleReciprocal(v+13.0*L*(9.0*
|
|
illuminant_tristimulus[illuminant].y/
|
|
(illuminant_tristimulus[illuminant].x+15.0*
|
|
illuminant_tristimulus[illuminant].y+3.0*
|
|
illuminant_tristimulus[illuminant].z))))-5.0))+5.0*(*Y));
|
|
*Z=(*X*(((52.0*L*PerceptibleReciprocal(u+13.0*L*(4.0*
|
|
illuminant_tristimulus[illuminant].x/
|
|
(illuminant_tristimulus[illuminant].x+15.0*
|
|
illuminant_tristimulus[illuminant].y+3.0*
|
|
illuminant_tristimulus[illuminant].z))))-1.0)/3.0))-5.0*(*Y);
|
|
}
|
|
|
|
static inline void ConvertProPhotoToXYZ(const double red,const double green,
|
|
const double blue,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
/*
|
|
Convert ProPhoto to XYZ colorspace.
|
|
*/
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
r=QuantumScale*DecodePixelGamma(red);
|
|
g=QuantumScale*DecodePixelGamma(green);
|
|
b=QuantumScale*DecodePixelGamma(blue);
|
|
*X=0.7977604896723027*r+0.13518583717574031*g+0.03134934958152480000*b;
|
|
*Y=0.2880711282292934*r+0.71184321781010140*g+0.00008565396060525902*b;
|
|
*Z=0.0000000000000000*r+0.00000000000000000*g+0.82510460251046010000*b;
|
|
}
|
|
|
|
static inline void ConvertRGBToXYZ(const double red,const double green,
|
|
const double blue,double *X,double *Y,double *Z)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
/*
|
|
Convert RGB to XYZ colorspace.
|
|
*/
|
|
assert(X != (double *) NULL);
|
|
assert(Y != (double *) NULL);
|
|
assert(Z != (double *) NULL);
|
|
r=QuantumScale*DecodePixelGamma(red);
|
|
g=QuantumScale*DecodePixelGamma(green);
|
|
b=QuantumScale*DecodePixelGamma(blue);
|
|
*X=0.4124564*r+0.3575761*g+0.1804375*b;
|
|
*Y=0.2126729*r+0.7151522*g+0.0721750*b;
|
|
*Z=0.0193339*r+0.1191920*g+0.9503041*b;
|
|
}
|
|
|
|
static inline void ConvertXYZToAdobe98(const double X,const double Y,
|
|
const double Z,double *red,double *green,double *blue)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
assert(red != (double *) NULL);
|
|
assert(green != (double *) NULL);
|
|
assert(blue != (double *) NULL);
|
|
r=2.041587903810746500*X-0.56500697427885960*Y-0.34473135077832956*Z;
|
|
g=(-0.969243636280879500)*X+1.87596750150772020*Y+0.04155505740717557*Z;
|
|
b=0.013444280632031142*X-0.11836239223101838*Y+1.01517499439120540*Z;
|
|
*red=EncodePixelGamma(QuantumRange*r);
|
|
*green=EncodePixelGamma(QuantumRange*g);
|
|
*blue=EncodePixelGamma(QuantumRange*b);
|
|
}
|
|
|
|
static inline void ConvertXYZToDisplayP3(const double X,const double Y,
|
|
const double Z,double *red,double *green,double *blue)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
assert(red != (double *) NULL);
|
|
assert(green != (double *) NULL);
|
|
assert(blue != (double *) NULL);
|
|
r=2.49349691194142500*X-0.93138361791912390*Y-0.402710784450716840*Z;
|
|
g=(-0.82948896956157470)*X+1.76266406031834630*Y+0.023624685841943577*Z;
|
|
b=0.03584583024378447*X-0.07617238926804182*Y+0.956884524007687200*Z;
|
|
*red=EncodePixelGamma(QuantumRange*r);
|
|
*green=EncodePixelGamma(QuantumRange*g);
|
|
*blue=EncodePixelGamma(QuantumRange*b);
|
|
}
|
|
|
|
static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
|
|
const IlluminantType illuminant,double *L,double *a,double *b)
|
|
{
|
|
double
|
|
x,
|
|
y,
|
|
z;
|
|
|
|
assert(L != (double *) NULL);
|
|
assert(a != (double *) NULL);
|
|
assert(b != (double *) NULL);
|
|
if ((X/illuminant_tristimulus[illuminant].x) > CIEEpsilon)
|
|
x=pow(X/illuminant_tristimulus[illuminant].x,1.0/3.0);
|
|
else
|
|
x=(CIEK*X/illuminant_tristimulus[illuminant].x+16.0)/116.0;
|
|
if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
|
|
y=pow(Y/illuminant_tristimulus[illuminant].y,1.0/3.0);
|
|
else
|
|
y=(CIEK*Y/illuminant_tristimulus[illuminant].y+16.0)/116.0;
|
|
if ((Z/illuminant_tristimulus[illuminant].z) > CIEEpsilon)
|
|
z=pow(Z/illuminant_tristimulus[illuminant].z,1.0/3.0);
|
|
else
|
|
z=(CIEK*Z/illuminant_tristimulus[illuminant].z+16.0)/116.0;
|
|
*L=((116.0*y)-16.0)/100.0;
|
|
*a=(500.0*(x-y))/255.0+0.5;
|
|
*b=(200.0*(y-z))/255.0+0.5;
|
|
}
|
|
|
|
static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
|
|
const IlluminantType illuminant,double *L,double *u,double *v)
|
|
{
|
|
double
|
|
alpha;
|
|
|
|
assert(L != (double *) NULL);
|
|
assert(u != (double *) NULL);
|
|
assert(v != (double *) NULL);
|
|
if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
|
|
*L=(double) (116.0*pow(Y/illuminant_tristimulus[illuminant].y,
|
|
1.0/3.0)-16.0);
|
|
else
|
|
*L=CIEK*(Y/illuminant_tristimulus[illuminant].y);
|
|
alpha=PerceptibleReciprocal(X+15.0*Y+3.0*Z);
|
|
*u=13.0*(*L)*((4.0*alpha*X)-(4.0*illuminant_tristimulus[illuminant].x/
|
|
(illuminant_tristimulus[illuminant].x+15.0*
|
|
illuminant_tristimulus[illuminant].y+3.0*
|
|
illuminant_tristimulus[illuminant].z)));
|
|
*v=13.0*(*L)*((9.0*alpha*Y)-(9.0*illuminant_tristimulus[illuminant].y/
|
|
(illuminant_tristimulus[illuminant].x+15.0*
|
|
illuminant_tristimulus[illuminant].y+3.0*
|
|
illuminant_tristimulus[illuminant].z)));
|
|
*L/=100.0;
|
|
*u=(*u+134.0)/354.0;
|
|
*v=(*v+140.0)/262.0;
|
|
}
|
|
|
|
static inline void ConvertXYZToProPhoto(const double X,const double Y,
|
|
const double Z,double *red,double *green,double *blue)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
assert(red != (double *) NULL);
|
|
assert(green != (double *) NULL);
|
|
assert(blue != (double *) NULL);
|
|
r=1.3457989731028281*X-0.25558010007997534*Y-0.05110628506753401*Z;
|
|
g=(-0.5446224939028347)*X+1.50823274131327810*Y+0.02053603239147973*Z;
|
|
b=0.0000000000000000*X+0.0000000000000000*Y+1.21196754563894540*Z;
|
|
*red=EncodePixelGamma(QuantumRange*r);
|
|
*green=EncodePixelGamma(QuantumRange*g);
|
|
*blue=EncodePixelGamma(QuantumRange*b);
|
|
}
|
|
|
|
static inline void ConvertXYZToRGB(const double X,const double Y,const double Z,
|
|
double *red,double *green,double *blue)
|
|
{
|
|
double
|
|
b,
|
|
g,
|
|
r;
|
|
|
|
assert(red != (double *) NULL);
|
|
assert(green != (double *) NULL);
|
|
assert(blue != (double *) NULL);
|
|
r=3.2404542*X-1.5371385*Y-0.4985314*Z;
|
|
g=(-0.9692660)*X+1.8760108*Y+0.0415560*Z;
|
|
b=0.0556434*X-0.2040259*Y+1.0572252*Z;
|
|
*red=EncodePixelGamma(QuantumRange*r);
|
|
*green=EncodePixelGamma(QuantumRange*g);
|
|
*blue=EncodePixelGamma(QuantumRange*b);
|
|
}
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
}
|
|
#endif
|
|
|
|
#endif
|