@@ -127,6 +127,104 @@ public void ApplyPiecewise(double boostPercentage = 0)
127127 }
128128 }
129129
130+ public void ApplyToneMappingCurve ( double maxInputNits = 400 , double maxOutputNits = 400 , double curve_like = 400 )
131+ {
132+ int lutSize = 1024 ;
133+ bool lutExist = true ;
134+ if ( RegammaLUT == null )
135+ {
136+ lutExist = false ;
137+ RegammaLUT = new double [ 3 , lutSize ] ;
138+ }
139+
140+ for ( int i = 0 ; i < lutSize ; i ++ )
141+ {
142+ double N = lutExist ? RegammaLUT [ 0 , i ] : ( double ) i / ( lutSize - 1 ) ;
143+ double L = InversePQ ( N ) * 10000 * ( maxInputNits / curve_like ) ;
144+ double numerator = L * ( maxInputNits + ( L / Math . Pow ( maxOutputNits / curve_like , 2 ) ) ) ;
145+ double L_d = numerator / ( maxInputNits + L ) ;
146+ double N_prime = PQ ( L_d / 10000 ) ;
147+
148+ N_prime = Math . Max ( 0.0 , Math . Min ( 1.0 , N_prime ) ) ;
149+
150+ for ( int c = 0 ; c < 3 ; c ++ )
151+ {
152+ RegammaLUT [ c , i ] = N_prime ;
153+ }
154+ }
155+ }
156+
157+
158+ public void ApplyToneMappingCurveGamma ( double maxInputNits = 400 , double maxOutputNits = 400 , double curve_like = 400 )
159+ {
160+ int lutSize = 1024 ;
161+ bool lutExist = true ;
162+ if ( RegammaLUT == null )
163+ {
164+ lutExist = false ;
165+ RegammaLUT = new double [ 3 , lutSize ] ;
166+ }
167+
168+ double L_target = ( 1 * ( PQ ( ( curve_like ) / 10000.0 ) / PQ ( ( maxInputNits ) / 10000.0 ) ) ) ;
169+ double L_target_prime = 1 * ( PQ ( ( curve_like ) / 10000 ) / PQ ( ( maxOutputNits ) / 10000.0 ) ) ;
170+ double difference = L_target_prime ;
171+ for ( int i = 0 ; i < lutSize ; i ++ )
172+ {
173+ double N = lutExist ? RegammaLUT [ 0 , i ] : ( double ) i / ( lutSize - 1 ) ;
174+ double N_converted = N * difference ;
175+ double L = InversePQ ( N_converted ) * 10000 * ( maxInputNits / curve_like ) ;
176+
177+ double N_prime = PQ ( L / 10000 ) ;
178+ N_prime = Math . Max ( 0.0 , Math . Min ( 1.0 , N_prime ) ) ;
179+ for ( int c = 0 ; c < 3 ; c ++ )
180+ {
181+ RegammaLUT [ c , i ] = N_prime ;
182+ }
183+ }
184+ }
185+
186+ // PQ EOTF function: converts luminance (cd/m^2) to normalized signal value
187+ private double PQ ( double L )
188+ {
189+ double m1 = 0.1593017578125 ;
190+ double m2 = 78.84375 ;
191+ double c1 = 0.8359375 ;
192+ double c2 = 18.8515625 ;
193+ double c3 = 18.6875 ;
194+
195+ double Lm1 = Math . Pow ( L , m1 ) ;
196+ double numerator = c1 + c2 * Lm1 ;
197+ double denominator = 1 + c3 * Lm1 ;
198+ double N = Math . Pow ( numerator / denominator , m2 ) ;
199+
200+ return N ;
201+ }
202+
203+ // Inverse PQ EOTF function: converts normalized signal value to luminance (cd/m^2)
204+ private double InversePQ ( double N )
205+ {
206+ double m1 = 0.1593017578125 ;
207+ double m2 = 78.84375 ;
208+ double c1 = 0.8359375 ;
209+ double c2 = 18.8515625 ;
210+ double c3 = 18.6875 ;
211+
212+ double N1_m2 = Math . Pow ( N , 1.0 / m2 ) ;
213+ double numerator = N1_m2 - c1 ;
214+ double denominator = c2 - c3 * N1_m2 ;
215+
216+ double Lm1 = numerator / denominator ;
217+
218+ // Ensure Lm1 is non-negative to avoid invalid values
219+ Lm1 = Math . Max ( Lm1 , 0.0 ) ;
220+
221+ double L = Math . Pow ( Lm1 , 1.0 / m1 ) ;
222+
223+ return L ;
224+ }
225+
226+
227+
130228 public void ApplyGamma ( double gamma = 2.2 , double shadowDetailBoost = 0 )
131229 {
132230 var lutSize = 1024 ;
@@ -995,7 +1093,23 @@ public IccProfile CreateIcc(GenerateProfileCommand command)
9951093 else if ( command . SDRTransferFunction == SDRTransferFunction . BT_1886 )
9961094 {
9971095 MHC2 . ApplySdrAcm ( 120 , 0.03 , 2.4 , command . SDRBrightnessBoost , command . ShadowDetailBoost ) ;
998- }
1096+ } else if ( command . SDRTransferFunction == SDRTransferFunction . ToneMappedPiecewise )
1097+ {
1098+
1099+ double from_nits = command . ToneMappingFromLuminance ;
1100+
1101+ double to_nits = command . ToneMappingToLuminance ;
1102+ double numerator = to_nits / from_nits ;
1103+
1104+ double gamma_like = ( command . ToneMappingToLuminance / command . HdrGammaMultiplier ) / numerator ;
1105+ double curve_like = ( command . ToneMappingToLuminance / command . HdrBrightnessMultiplier ) / numerator ;
1106+
1107+ MHC2 . ApplyToneMappingCurve ( from_nits , to_nits , to_nits ) ;
1108+
1109+ MHC2 . ApplyToneMappingCurve ( from_nits , from_nits , curve_like ) ;
1110+ MHC2 . ApplyToneMappingCurveGamma ( from_nits , from_nits , gamma_like ) ;
1111+
1112+ }
9991113 }
10001114 else
10011115 {
@@ -1233,4 +1347,4 @@ public IccProfile CreateCscIcc(RgbPrimaries? sourcePrimaries = null, string sour
12331347 }
12341348
12351349 }
1236- }
1350+ }
0 commit comments