
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5596 8e941d3f-bd1b-0410-a28a-d453659cc2b4
326 lines
6.6 KiB
ObjectPascal
326 lines
6.6 KiB
ObjectPascal
unit RGBCIEUtils;
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, LCLIntf, Graphics, Math;
|
|
|
|
const
|
|
{// Observer= 2°, Illuminant= D65 - Daylignt
|
|
ref_X = 95.047;
|
|
ref_Z = 108.883;
|
|
// Observer= 10°, Illuminant= D65 - Daylight
|
|
ref_X = 94.811;
|
|
ref_Z = 35.2;
|
|
|
|
// Observer= 2°, Illuminant= A - Incadescent
|
|
ref_X = 109.850;
|
|
ref_Z = 35.585;
|
|
// Observer= 10°, Illuminant= A - Incadescent
|
|
ref_X = 111.144;
|
|
ref_Z = 35.2;
|
|
|
|
// Observer= 2°, Illuminant= C
|
|
ref_X = 98.074;
|
|
ref_Z = 118.232;
|
|
// Observer= 10°, Illuminant= C
|
|
ref_X = 97.285;
|
|
ref_Z = 116.145;
|
|
}
|
|
// Observer= 2°, Illuminant= D50
|
|
ref_X = 96.422;
|
|
ref_Z = 82.521;{
|
|
// Observer= 10°, Illuminant= D50 - Photoshop
|
|
ref_X = 96.72;
|
|
ref_Z = 81.427; }
|
|
|
|
{// Observer= 2°, Illuminant= D55
|
|
ref_X = 95.682;
|
|
ref_Z = 92.149;
|
|
// Observer= 10°, Illuminant= D55
|
|
ref_X = 95.799;
|
|
ref_Z = 90.926;
|
|
|
|
// Observer= 2°, Illuminant= D75
|
|
ref_X = 94.972;
|
|
ref_Z = 122.638;
|
|
// Observer= 10°, Illuminant= D75
|
|
ref_X = 94.416;
|
|
ref_Z = 12.641;
|
|
|
|
// Observer= 2°, Illuminant= F2 - Fluorescent
|
|
ref_X = 99.187;
|
|
ref_Z = 67.395;
|
|
// Observer= 10°, Illuminant= F2 - Fluorescent
|
|
ref_X = 103.28;
|
|
ref_Z = 69.026;
|
|
|
|
// Observer= 2°, Illuminant= F7
|
|
ref_X = 95.044;
|
|
ref_Z = 108.755;
|
|
// Observer= 10°, Illuminant= F7
|
|
ref_X = 95.792;
|
|
ref_Z = 107.678;
|
|
|
|
// Observer= 2°, Illuminant= F11
|
|
ref_X = 100.966;
|
|
ref_Z = 64.370;
|
|
// Observer= 10°, Illuminant= F11
|
|
ref_X = 103.866;
|
|
ref_Z = 65.627; }
|
|
|
|
type
|
|
xyz = record
|
|
x: Double;
|
|
y: Double;
|
|
z: Double;
|
|
end;
|
|
|
|
function LabToXYZ(l, a, b: double): xyz;
|
|
function XYZToRGB(space: xyz): TColor;
|
|
function LabToRGB(l, a, b: double): TColor;
|
|
function RGBToXYZ(c: TColor): xyz;
|
|
procedure RGBToLab(clr: TColor; var l, a, b: double);
|
|
procedure XYZToLab(space: xyz; var l, a, b: double);
|
|
procedure LCHToLab(lum, c, h: double; var l, a, b: double);
|
|
procedure LabToLCH(l, a, b: double; var lum, c, h: double);
|
|
function LCHToRGB(l, c, h: double): TColor;
|
|
procedure RGBToLCH(clr: TColor; var l, c, h: double);
|
|
function GetCIEXValue(c: TColor): double;
|
|
function GetCIEYValue(c: TColor): double;
|
|
function GetCIEZValue(c: TColor): double;
|
|
function GetCIELValue(c: TColor): double;
|
|
function GetCIEAValue(c: TColor): double;
|
|
function GetCIEBValue(c: TColor): double;
|
|
function GetCIECValue(c: TColor): double;
|
|
function GetCIEHValue(c: TColor): double;
|
|
|
|
implementation
|
|
|
|
uses
|
|
mbUtils;
|
|
|
|
function LabToXYZ(l, a, b: double): xyz;
|
|
var
|
|
x, y, z: double;
|
|
begin
|
|
y := (l + 16)/116;
|
|
x := a/500 + y;
|
|
z := y - b/200;
|
|
if y > 0.2069 then
|
|
y := IntPower(y, 3)
|
|
else
|
|
y := (y - 0.138)/7.787;
|
|
if x > 0.2069 then
|
|
x := IntPower(x, 3)
|
|
else
|
|
x := (x - 0.138)/7.787;
|
|
if z > 0.2069 then
|
|
z := IntPower(z, 3)
|
|
else
|
|
z := (z - 0.138)/7.787;
|
|
Result.x := ref_X * x;
|
|
Result.y := 100 * y;
|
|
Result.z := ref_Z * z;
|
|
end;
|
|
|
|
function XYZToRGB(space: xyz): TColor;
|
|
// see:
|
|
// https://de.mathworks.com/matlabcentral/fileexchange/28790-colorspace-transformations/content/colorspace/colorspace.html?requestedDomain=www.mathworks.com
|
|
var
|
|
r, g, b, x, y, z: double;
|
|
begin
|
|
x := space.x/100;
|
|
y := space.y/100;
|
|
z := space.z/100;
|
|
r := x * 3.2406 + y * (-1.5372) + z * (-0.49);
|
|
g := x * (-0.969) + y * 1.8758 + z * 0.0415;
|
|
b := x * 0.0557 + y * (-0.2040) + z * 1.0570;
|
|
if r > 0.00313 then
|
|
r := 1.055 * Power(r, 1/2.4) - 0.055
|
|
else
|
|
r := 12.92 * r;
|
|
if g > 0.00313 then
|
|
g := 1.055 * Power(g, 1/2.4) - 0.055
|
|
else
|
|
g := 12.92 * g;
|
|
if b > 0.00313 then
|
|
b := 1.055 * Power(b, 1/2.4) - 0.055
|
|
else
|
|
b := 12.92 * b;
|
|
|
|
Clamp(r, 0, 1);
|
|
Clamp(g, 0, 1);
|
|
Clamp(b, 0, 1);
|
|
Result := RGB(Round(r*255), Round(g*255), Round(b*255));
|
|
end;
|
|
|
|
function LabToRGB(l, a, b: double): TColor;
|
|
begin
|
|
Result := XYZToRGB(LabToXYZ(l, a, b));
|
|
end;
|
|
|
|
function RGBToXYZ(c: TColor): xyz;
|
|
var
|
|
r, g, b: double;
|
|
begin
|
|
r := GetRValue(c)/255;
|
|
g := GetGValue(c)/255;
|
|
b := GetBValue(c)/255;
|
|
if r > 0.04045 then
|
|
r := Power((r + 0.055)/1.055, 2.4)
|
|
else
|
|
r := r/12.92;
|
|
if g > 0.04045 then
|
|
g := Power((g + 0.055)/1.055, 2.4)
|
|
else
|
|
g := g/12.92;
|
|
if b > 0.04045 then
|
|
b := Power((b + 0.055)/1.055, 2.4)
|
|
else
|
|
b := b/12.92;
|
|
r := r * 100;
|
|
g := g * 100;
|
|
b := b * 100;
|
|
// Observer= 2°, Illuminant= D65
|
|
Result.x := r * 0.4124 + g * 0.3576 + b * 0.1805;
|
|
Result.y := r * 0.2126 + g * 0.7152 + b * 0.0722;
|
|
Result.z := r * 0.0193 + g * 0.1192 + b * 0.9505;
|
|
end;
|
|
|
|
procedure XYZToLab(space: xyz; var l, a, b: Double);
|
|
var
|
|
x, y, z: double;
|
|
begin
|
|
x := space.x/ref_X;
|
|
y := space.y/100;
|
|
z := space.z/ref_Z;
|
|
if x > 0.008856 then
|
|
x := Power(x, 1/3)
|
|
else
|
|
x := (7.787*x) + 0.138;
|
|
if y > 0.008856 then
|
|
y := Power(y, 1/3)
|
|
else
|
|
y := (7.787*y) + 0.138;
|
|
if z > 0.008856 then
|
|
z := Power(z, 1/3)
|
|
else
|
|
z := (7.787*z) + 0.138;
|
|
l := (116*y) - 16;
|
|
a := 500 * (x - y);
|
|
b := 200 * (y - z);
|
|
Clamp(l, 0, 100);
|
|
Clamp(a, -128, 127);
|
|
Clamp(b, -128, 127);
|
|
end;
|
|
|
|
procedure RGBToLab(clr: TColor; var l, a, b: Double);
|
|
var
|
|
s: xyz;
|
|
begin
|
|
s := RGBToXYZ(clr);
|
|
XYZToLab(s, l, a, b);
|
|
end;
|
|
|
|
procedure LCHToLab(lum, c, h: double; var l, a, b: double);
|
|
begin
|
|
l := lum;
|
|
a := cos(DegToRad(h)) * c;
|
|
b := sin(DegToRad(h)) * c;
|
|
end;
|
|
|
|
procedure LabToLCH(l, a, b: double; var lum, c, h: double);
|
|
begin
|
|
h := ArcTan2(b, a);
|
|
if h > 0 then
|
|
h := (h/pi) * 180
|
|
else
|
|
h := 360 - (abs(h)/pi) * 180;
|
|
lum := l;
|
|
c := SQRT(a*a + b*b);
|
|
end;
|
|
|
|
procedure RGBToLCH(clr: TColor; var l, c, h: double);
|
|
var
|
|
a: Double = 0;
|
|
b: Double = 0;
|
|
begin
|
|
RGBToLab(clr, l, a, b);
|
|
LabToLCH(l, a, b, l, c, h);
|
|
end;
|
|
|
|
function LCHToRGB(l, c, h: double): TColor;
|
|
var
|
|
lum: Double = 0;
|
|
a: Double = 0;
|
|
b: double = 0;
|
|
begin
|
|
LCHToLab(l, c, h, lum, a, b);
|
|
Result := LabToRGB(lum, a, b);
|
|
end;
|
|
|
|
function GetCIEXValue(c: TColor): double;
|
|
var
|
|
d: xyz;
|
|
begin
|
|
d := RGBToXYZ(c);
|
|
Result := d.x;
|
|
end;
|
|
|
|
function GetCIEYValue(c: TColor): double;
|
|
var
|
|
d: xyz;
|
|
begin
|
|
d := RGBToXYZ(c);
|
|
Result := d.y;
|
|
end;
|
|
|
|
function GetCIEZValue(c: TColor): double;
|
|
var
|
|
d: xyz;
|
|
begin
|
|
d := RGBToXYZ(c);
|
|
Result := d.z;
|
|
end;
|
|
|
|
function GetCIELValue(c: TColor): double;
|
|
var
|
|
d: Double = 0;
|
|
begin
|
|
XYZToLab(RGBToXYZ(c), Result{%H-}, d, d);
|
|
end;
|
|
|
|
function GetCIEAValue(c: TColor): double;
|
|
var
|
|
d: double = 0;
|
|
begin
|
|
XYZToLab(RGBToXYZ(c), d, Result{%H-}, d);
|
|
end;
|
|
|
|
function GetCIEBValue(c: TColor): double;
|
|
var
|
|
d: double = 0;
|
|
begin
|
|
XYZToLab(RGBToXYZ(c), d, d, Result{%H-});
|
|
end;
|
|
|
|
function GetCIECValue(c: TColor): double;
|
|
var
|
|
d: double = 0;
|
|
begin
|
|
Result := 0.0;
|
|
RGBToLCH(c, d, Result, d);
|
|
end;
|
|
|
|
function GetCIEHValue(c: TColor): double;
|
|
var
|
|
d: double = 0;
|
|
begin
|
|
Result := 0.0;
|
|
RGBToLCH(c, d, d, Result);
|
|
end;
|
|
|
|
end.
|
|
|