| 1 | unit BGRAColorspace;
|
|---|
| 2 |
|
|---|
| 3 | {$mode objfpc}{$H+}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, SysUtils, BGRABitmapTypes;
|
|---|
| 9 |
|
|---|
| 10 | type
|
|---|
| 11 | { TCIERGB }
|
|---|
| 12 |
|
|---|
| 13 | TCIERGB = packed record
|
|---|
| 14 | //components are between 0 and 1
|
|---|
| 15 | R,G,B,A: single;
|
|---|
| 16 | function ToBGRA: TBGRAPixel;
|
|---|
| 17 | procedure FromBGRA(AValue: TBGRAPixel);
|
|---|
| 18 | function ToExpanded: TExpandedPixel;
|
|---|
| 19 | procedure FromExpanded(AValue: TExpandedPixel);
|
|---|
| 20 | end;
|
|---|
| 21 |
|
|---|
| 22 | { TCIEXYZ }
|
|---|
| 23 |
|
|---|
| 24 | TCIEXYZ = packed record
|
|---|
| 25 | //components are between 0 and 1
|
|---|
| 26 | X, Y, Z,
|
|---|
| 27 | A: single;
|
|---|
| 28 | function ToRGB: TCIERGB;
|
|---|
| 29 | procedure FromRGB(AValue: TCIERGB);
|
|---|
| 30 | end;
|
|---|
| 31 |
|
|---|
| 32 | { TBGRAPixelColorspaceHelper }
|
|---|
| 33 |
|
|---|
| 34 | TBGRAPixelColorspaceHelper = record helper(TBGRAPixelHelper) for TBGRAPixel
|
|---|
| 35 | function ToXYZ: TCIEXYZ;
|
|---|
| 36 | procedure FromXYZ(const AValue: TCIEXYZ);
|
|---|
| 37 | end;
|
|---|
| 38 |
|
|---|
| 39 | { TExpandedPixelColorspaceHelper }
|
|---|
| 40 |
|
|---|
| 41 | TExpandedPixelColorspaceHelper = record helper(TExpandedPixelHelper) for TExpandedPixel
|
|---|
| 42 | function ToXYZ: TCIEXYZ;
|
|---|
| 43 | procedure FromXYZ(const AValue: TCIEXYZ);
|
|---|
| 44 | end;
|
|---|
| 45 |
|
|---|
| 46 | procedure RGBToXYZ(R, G, B: single; out X, Y, Z: single);
|
|---|
| 47 | procedure XYZToRGB(X, Y, Z: single; out R, G, B: single);
|
|---|
| 48 |
|
|---|
| 49 | implementation
|
|---|
| 50 |
|
|---|
| 51 | function ClampF(AValue,AMin,AMax: single): single;
|
|---|
| 52 | begin
|
|---|
| 53 | if AValue <= AMin then result := AMin
|
|---|
| 54 | else if AValue >= AMax then result := AMax
|
|---|
| 55 | else result := AValue;
|
|---|
| 56 | end;
|
|---|
| 57 |
|
|---|
| 58 | procedure RGBToXYZ(R, G, B: single; out X, Y, Z: single);
|
|---|
| 59 | begin
|
|---|
| 60 | // Observer= 2°, Illuminant= D65
|
|---|
| 61 | X := R * 0.4124 + G * 0.3576 + B * 0.1805;
|
|---|
| 62 | Y := R * 0.2126 + G * 0.7152 + B * 0.0722;
|
|---|
| 63 | Z := R * 0.0193 + G * 0.1192 + B * 0.9505;
|
|---|
| 64 | end;
|
|---|
| 65 |
|
|---|
| 66 | procedure XYZToRGB(X, Y, Z: single; out R, G, B: single);
|
|---|
| 67 | begin
|
|---|
| 68 | R := ClampF(X * 3.2406 + Y * (-1.5372) + Z * (-0.49), 0, 1);
|
|---|
| 69 | G := ClampF(X * (-0.969) + Y * 1.8758 + Z * 0.0415, 0, 1);
|
|---|
| 70 | B := ClampF(X * 0.0557 + Y * (-0.2040) + Z * 1.0570, 0, 1);
|
|---|
| 71 | end;
|
|---|
| 72 |
|
|---|
| 73 | { TCIERGB }
|
|---|
| 74 |
|
|---|
| 75 | function TCIERGB.ToBGRA: TBGRAPixel;
|
|---|
| 76 | var
|
|---|
| 77 | redF,greenF,blueF: single;
|
|---|
| 78 | begin
|
|---|
| 79 | if r > 0.00313 then
|
|---|
| 80 | redF := 1.055 * Power(r, 1 / 2.4) - 0.055
|
|---|
| 81 | else
|
|---|
| 82 | redF := 12.92 * r;
|
|---|
| 83 | if g > 0.00313 then
|
|---|
| 84 | greenF := 1.055 * Power(g, 1 / 2.4) - 0.055
|
|---|
| 85 | else
|
|---|
| 86 | greenF := 12.92 * g;
|
|---|
| 87 | if b > 0.00313 then
|
|---|
| 88 | blueF := 1.055 * Power(b, 1 / 2.4) - 0.055
|
|---|
| 89 | else
|
|---|
| 90 | blueF := 12.92 * b;
|
|---|
| 91 |
|
|---|
| 92 | result.red := round(clampF(redF,0,1)*255);
|
|---|
| 93 | result.green := round(clampF(greenF,0,1)*255);
|
|---|
| 94 | result.blue := round(clampF(blueF,0,1)*255);
|
|---|
| 95 | result.alpha := round(clampF(A,0,1)*255);
|
|---|
| 96 | end;
|
|---|
| 97 |
|
|---|
| 98 | procedure TCIERGB.FromBGRA(AValue: TBGRAPixel);
|
|---|
| 99 | begin
|
|---|
| 100 | R := AValue.red/255;
|
|---|
| 101 | G := AValue.green/255;
|
|---|
| 102 | B := AValue.blue/255;
|
|---|
| 103 | A := AValue.alpha/255;
|
|---|
| 104 |
|
|---|
| 105 | if R > 0.04045 then
|
|---|
| 106 | R := Power((R + 0.055) / 1.055, 2.4)
|
|---|
| 107 | else
|
|---|
| 108 | R := R / 12.92;
|
|---|
| 109 | if G > 0.04045 then
|
|---|
| 110 | G := Power((G + 0.055) / 1.055, 2.4)
|
|---|
| 111 | else
|
|---|
| 112 | G := G / 12.92;
|
|---|
| 113 | if B > 0.04045 then
|
|---|
| 114 | B := Power((B + 0.055) / 1.055, 2.4)
|
|---|
| 115 | else
|
|---|
| 116 | B := B / 12.92;
|
|---|
| 117 | end;
|
|---|
| 118 |
|
|---|
| 119 | function TCIERGB.ToExpanded: TExpandedPixel;
|
|---|
| 120 | begin
|
|---|
| 121 | result.red := round(ClampF(R,0,1)*65535);
|
|---|
| 122 | result.green := round(ClampF(G,0,1)*65535);
|
|---|
| 123 | result.blue := round(ClampF(B,0,1)*65535);
|
|---|
| 124 | result.alpha := round(ClampF(A,0,1)*65535);
|
|---|
| 125 | end;
|
|---|
| 126 |
|
|---|
| 127 | procedure TCIERGB.FromExpanded(AValue: TExpandedPixel);
|
|---|
| 128 | begin
|
|---|
| 129 | R := AValue.red/65535;
|
|---|
| 130 | G := AValue.green/65535;
|
|---|
| 131 | B := AValue.blue/65535;
|
|---|
| 132 | A := AValue.alpha/65535;
|
|---|
| 133 | end;
|
|---|
| 134 |
|
|---|
| 135 | { TCIEXYZ }
|
|---|
| 136 |
|
|---|
| 137 | function TCIEXYZ.ToBGRA: TBGRAPixel;
|
|---|
| 138 | begin
|
|---|
| 139 | result.FromXYZ(self);
|
|---|
| 140 | end;
|
|---|
| 141 |
|
|---|
| 142 | procedure TCIEXYZ.FromBGRA(AValue: TBGRAPixel);
|
|---|
| 143 | begin
|
|---|
| 144 | self := AValue.ToXYZ;
|
|---|
| 145 | end;
|
|---|
| 146 |
|
|---|
| 147 | function TCIEXYZ.ToExpanded: TExpandedPixel;
|
|---|
| 148 | begin
|
|---|
| 149 | result.FromXYZ(self);
|
|---|
| 150 | end;
|
|---|
| 151 |
|
|---|
| 152 | procedure TCIEXYZ.FromExpanded(AValue: TExpandedPixel);
|
|---|
| 153 | begin
|
|---|
| 154 | self := AValue.ToXYZ;
|
|---|
| 155 | end;
|
|---|
| 156 |
|
|---|
| 157 | function TCIEXYZ.ToRGB: TCIERGB;
|
|---|
| 158 | begin
|
|---|
| 159 | XYZToRGB(X,Y,Z, result.R,result.G,result.B);
|
|---|
| 160 | result.A := A;
|
|---|
| 161 | end;
|
|---|
| 162 |
|
|---|
| 163 | procedure TCIEXYZ.FromRGB(AValue: TCIERGB);
|
|---|
| 164 | begin
|
|---|
| 165 | RGBToXYZ(AValue.R,AValue.G,AValue.B, X,Y,Z);
|
|---|
| 166 | A := AValue.A;
|
|---|
| 167 | end;
|
|---|
| 168 |
|
|---|
| 169 | { TExpandedPixelColorspaceHelper }
|
|---|
| 170 |
|
|---|
| 171 | function TExpandedPixelColorspaceHelper.ToXYZ: TCIEXYZ;
|
|---|
| 172 | var RGB: TCIERGB;
|
|---|
| 173 | begin
|
|---|
| 174 | RGB.FromExpanded(Self);
|
|---|
| 175 | result.FromRGB(RGB);
|
|---|
| 176 | end;
|
|---|
| 177 |
|
|---|
| 178 | procedure TExpandedPixelColorspaceHelper.FromXYZ(const AValue: TCIEXYZ);
|
|---|
| 179 | var redF,greenF,blueF: single;
|
|---|
| 180 | begin
|
|---|
| 181 | self := AValue.ToRGB.ToExpanded;
|
|---|
| 182 | end;
|
|---|
| 183 |
|
|---|
| 184 | { TBGRAPixelColorspaceHelper }
|
|---|
| 185 |
|
|---|
| 186 | function TBGRAPixelColorspaceHelper.ToXYZ: TCIEXYZ;
|
|---|
| 187 | var RGB: TCIERGB;
|
|---|
| 188 | begin
|
|---|
| 189 | RGB.FromBGRA(Self);
|
|---|
| 190 | result.FromRGB(RGB);
|
|---|
| 191 | end;
|
|---|
| 192 |
|
|---|
| 193 | procedure TBGRAPixelColorspaceHelper.FromXYZ(const AValue: TCIEXYZ);
|
|---|
| 194 | begin
|
|---|
| 195 | self := AValue.ToRGB.ToBGRA;
|
|---|
| 196 | end;
|
|---|
| 197 |
|
|---|
| 198 | end.
|
|---|
| 199 |
|
|---|