1 | unit GR32_Gamma;
|
---|
2 |
|
---|
3 | interface
|
---|
4 |
|
---|
5 | uses
|
---|
6 | GR32;
|
---|
7 |
|
---|
8 | { Gamma bias for line/pixel antialiasing }
|
---|
9 |
|
---|
10 | type
|
---|
11 | TGammaTable8Bit = array [Byte] of Byte;
|
---|
12 |
|
---|
13 | var
|
---|
14 | GAMMA_VALUE: Double;
|
---|
15 | GAMMA_ENCODING_TABLE: TGammaTable8Bit;
|
---|
16 | GAMMA_DECODING_TABLE: TGammaTable8Bit;
|
---|
17 |
|
---|
18 | const
|
---|
19 | DEFAULT_GAMMA: Double = 2.2;
|
---|
20 |
|
---|
21 | // set gamma
|
---|
22 | procedure SetGamma; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
|
---|
23 | procedure SetGamma(Gamma: Double); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
|
---|
24 | procedure SetGamma(Gamma: Double; var GammaTable: TGammaTable8Bit); overload;
|
---|
25 |
|
---|
26 | procedure Set_sRGB; overload;
|
---|
27 | procedure Set_sRGB(var GammaTable: TGammaTable8Bit); overload;
|
---|
28 | procedure SetInv_sRGB(var GammaTable: TGammaTable8Bit);
|
---|
29 |
|
---|
30 | // apply gamma
|
---|
31 | function ApplyGamma(Color: TColor32): TColor32; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
|
---|
32 | function ApplyInvGamma(Color: TColor32): TColor32; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
|
---|
33 | function ApplyCustomGamma(Color: TColor32; GammaTable: TGammaTable8Bit): TColor32; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
|
---|
34 |
|
---|
35 | procedure ApplyGamma(Color: PColor32Array; Length: Integer); overload;
|
---|
36 | procedure ApplyInvGamma(Color: PColor32Array; Length: Integer); overload;
|
---|
37 | procedure ApplyCustomGamma(Color: PColor32Array; Length: Integer; GammaTable: TGammaTable8Bit); overload;
|
---|
38 |
|
---|
39 | procedure ApplyGamma(Bitmap: TBitmap32); overload;
|
---|
40 | procedure ApplyInvGamma(Bitmap: TBitmap32); overload;
|
---|
41 | procedure ApplyCustomGamma(Bitmap: TBitmap32; GammaTable: TGammaTable8Bit); overload;
|
---|
42 | procedure ApplyCustomGamma(Bitmap: TBitmap32; Gamma: Double); overload;
|
---|
43 |
|
---|
44 | implementation
|
---|
45 |
|
---|
46 | uses
|
---|
47 | Math;
|
---|
48 |
|
---|
49 | function ApplyGamma(Color: TColor32): TColor32;
|
---|
50 | var
|
---|
51 | C: TColor32Entry absolute Color;
|
---|
52 | R: TColor32Entry absolute Result;
|
---|
53 | begin
|
---|
54 | C.R := GAMMA_ENCODING_TABLE[C.R];
|
---|
55 | C.G := GAMMA_ENCODING_TABLE[C.G];
|
---|
56 | C.B := GAMMA_ENCODING_TABLE[C.B];
|
---|
57 | end;
|
---|
58 |
|
---|
59 | function ApplyInvGamma(Color: TColor32): TColor32;
|
---|
60 | var
|
---|
61 | C: TColor32Entry absolute Color;
|
---|
62 | R: TColor32Entry absolute Result;
|
---|
63 | begin
|
---|
64 | C.R := GAMMA_DECODING_TABLE[C.R];
|
---|
65 | C.G := GAMMA_DECODING_TABLE[C.G];
|
---|
66 | C.B := GAMMA_DECODING_TABLE[C.B];
|
---|
67 | end;
|
---|
68 |
|
---|
69 | function ApplyCustomGamma(Color: TColor32; GammaTable: TGammaTable8Bit): TColor32;
|
---|
70 | var
|
---|
71 | C: TColor32Entry absolute Color;
|
---|
72 | R: TColor32Entry absolute Result;
|
---|
73 | begin
|
---|
74 | C.R := GammaTable[C.R];
|
---|
75 | C.G := GammaTable[C.G];
|
---|
76 | C.B := GammaTable[C.B];
|
---|
77 | end;
|
---|
78 |
|
---|
79 |
|
---|
80 | procedure ApplyGamma(Color: PColor32Array; Length: Integer);
|
---|
81 | var
|
---|
82 | Index: Integer;
|
---|
83 | begin
|
---|
84 | for Index := 0 to Length - 1 do
|
---|
85 | begin
|
---|
86 | PColor32Entry(Color)^.R := GAMMA_ENCODING_TABLE[PColor32Entry(Color)^.R];
|
---|
87 | PColor32Entry(Color)^.G := GAMMA_ENCODING_TABLE[PColor32Entry(Color)^.G];
|
---|
88 | PColor32Entry(Color)^.B := GAMMA_ENCODING_TABLE[PColor32Entry(Color)^.B];
|
---|
89 | Inc(Color);
|
---|
90 | end;
|
---|
91 | end;
|
---|
92 |
|
---|
93 | procedure ApplyInvGamma(Color: PColor32Array; Length: Integer);
|
---|
94 | var
|
---|
95 | Index: Integer;
|
---|
96 | begin
|
---|
97 | for Index := 0 to Length - 1 do
|
---|
98 | begin
|
---|
99 | PColor32Entry(Color)^.R := GAMMA_DECODING_TABLE[PColor32Entry(Color)^.R];
|
---|
100 | PColor32Entry(Color)^.G := GAMMA_DECODING_TABLE[PColor32Entry(Color)^.G];
|
---|
101 | PColor32Entry(Color)^.B := GAMMA_DECODING_TABLE[PColor32Entry(Color)^.B];
|
---|
102 | Inc(Color);
|
---|
103 | end;
|
---|
104 | end;
|
---|
105 |
|
---|
106 | procedure ApplyCustomGamma(Color: PColor32Array; Length: Integer;
|
---|
107 | GammaTable: TGammaTable8Bit);
|
---|
108 | var
|
---|
109 | Index: Integer;
|
---|
110 | begin
|
---|
111 | for Index := 0 to Length - 1 do
|
---|
112 | begin
|
---|
113 | PColor32Entry(Color)^.R := GammaTable[PColor32Entry(Color)^.R];
|
---|
114 | PColor32Entry(Color)^.G := GammaTable[PColor32Entry(Color)^.G];
|
---|
115 | PColor32Entry(Color)^.B := GammaTable[PColor32Entry(Color)^.B];
|
---|
116 | Inc(Color);
|
---|
117 | end;
|
---|
118 | end;
|
---|
119 |
|
---|
120 |
|
---|
121 | procedure ApplyGamma(Bitmap: TBitmap32);
|
---|
122 | begin
|
---|
123 | ApplyGamma(Bitmap.Bits, Bitmap.Width * Bitmap.Height);
|
---|
124 | end;
|
---|
125 |
|
---|
126 | procedure ApplyInvGamma(Bitmap: TBitmap32);
|
---|
127 | begin
|
---|
128 | ApplyInvGamma(Bitmap.Bits, Bitmap.Width * Bitmap.Height);
|
---|
129 | end;
|
---|
130 |
|
---|
131 | procedure ApplyCustomGamma(Bitmap: TBitmap32; GammaTable: TGammaTable8Bit);
|
---|
132 | begin
|
---|
133 | ApplyCustomGamma(Bitmap.Bits, Bitmap.Width * Bitmap.Height, GammaTable);
|
---|
134 | end;
|
---|
135 |
|
---|
136 | procedure ApplyCustomGamma(Bitmap: TBitmap32; Gamma: Double);
|
---|
137 | var
|
---|
138 | GammaTable: TGammaTable8Bit;
|
---|
139 | begin
|
---|
140 | if GAMMA_VALUE = Gamma then
|
---|
141 | ApplyGamma(Bitmap.Bits, Bitmap.Width * Bitmap.Height)
|
---|
142 | else
|
---|
143 | begin
|
---|
144 | SetGamma(Gamma, GammaTable);
|
---|
145 | ApplyCustomGamma(Bitmap.Bits, Bitmap.Width * Bitmap.Height, GammaTable);
|
---|
146 | end;
|
---|
147 | end;
|
---|
148 |
|
---|
149 |
|
---|
150 | { Gamma / Pixel Shape Correction table }
|
---|
151 |
|
---|
152 | procedure SetGamma;
|
---|
153 | begin
|
---|
154 | SetGamma(DEFAULT_GAMMA);
|
---|
155 | end;
|
---|
156 |
|
---|
157 | procedure SetGamma(Gamma: Double);
|
---|
158 | begin
|
---|
159 | GAMMA_VALUE := Gamma;
|
---|
160 |
|
---|
161 | // calculate default gamma tables
|
---|
162 | SetGamma(1 / Gamma, GAMMA_ENCODING_TABLE);
|
---|
163 | SetGamma(Gamma, GAMMA_DECODING_TABLE);
|
---|
164 | end;
|
---|
165 |
|
---|
166 | procedure SetGamma(Gamma: Double; var GammaTable: TGammaTable8Bit);
|
---|
167 | var
|
---|
168 | i: Integer;
|
---|
169 | begin
|
---|
170 | for i := 0 to $FF do
|
---|
171 | GammaTable[i] := Round($FF * Power(i * COne255th, Gamma));
|
---|
172 | end;
|
---|
173 |
|
---|
174 | procedure Set_sRGB;
|
---|
175 | begin
|
---|
176 | Set_sRGB(GAMMA_ENCODING_TABLE);
|
---|
177 | SetInv_sRGB(GAMMA_DECODING_TABLE);
|
---|
178 | end;
|
---|
179 |
|
---|
180 | procedure Set_sRGB(var GammaTable: TGammaTable8Bit);
|
---|
181 | var
|
---|
182 | i: Integer;
|
---|
183 | Value: Double;
|
---|
184 | const
|
---|
185 | CExp = 1 / 2.4;
|
---|
186 | begin
|
---|
187 | for i := 0 to $FF do
|
---|
188 | begin
|
---|
189 | Value := i * COne255th;
|
---|
190 | if (Value < 0.0031308) then
|
---|
191 | GammaTable[i] := Round($FF * Value * 12.92)
|
---|
192 | else
|
---|
193 | GammaTable[i] := Round($FF * (1.055 * Power(Value, CExp) - 0.055));
|
---|
194 | end;
|
---|
195 | end;
|
---|
196 |
|
---|
197 | procedure SetInv_sRGB(var GammaTable: TGammaTable8Bit);
|
---|
198 | var
|
---|
199 | i: Integer;
|
---|
200 | Value: Double;
|
---|
201 | begin
|
---|
202 | for i := 0 to $FF do
|
---|
203 | begin
|
---|
204 | Value := i * COne255th;
|
---|
205 | if (Value < 0.004045) then
|
---|
206 | GammaTable[i] := Round($FF * Value / 12.92)
|
---|
207 | else
|
---|
208 | GammaTable[i] := Round($FF * Power((Value + 0.055) / 1.055, 2.4));
|
---|
209 | end;
|
---|
210 | end;
|
---|
211 |
|
---|
212 | end.
|
---|