rainbow-dragon/Sources/ForgeColor/TransferFunction.swift

79 lines
2.4 KiB
Swift
Raw Permalink Normal View History

import Foundation
/// Camera log transfer functions. Constants from vendor whitepapers:
/// - ARRI LogC4 (ALEXA 35), ARRI LogC4 spec 2022
/// - RED Log3G10 v3, RED IPP2 whitepaper
/// - Sony S-Log3, Sony technical summary
public enum TransferFunction: String, Sendable, CaseIterable, Codable {
case logC4
case log3G10
case sLog3
case linear
/// Linear scene value -> encoded log signal (0..1 nominal).
public func encode(_ x: Float) -> Float {
switch self {
case .linear:
return x
case .logC4:
let c = LogC4.self
if x < c.t { return (x - c.t) / c.s }
return (log2(c.a * x + 64) - 6) / 14 * c.b + c.c
case .log3G10:
let c = Log3G10.self
let y = x + c.c
if y < 0 { return y * c.g }
return c.a * log10(y * c.b + 1)
case .sLog3:
let c = SLog3.self
if x >= c.linBreak {
return (420 + log10((x + 0.01) / 0.19) * 261.5) / 1023
}
return (x * (171.2102946929 - 95) / c.linBreak + 95) / 1023
}
}
/// Encoded log signal -> linear scene value.
public func decode(_ y: Float) -> Float {
switch self {
case .linear:
return y
case .logC4:
let c = LogC4.self
if y < 0 { return y * c.s + c.t }
return (exp2(14 * (y - c.c) / c.b + 6) - 64) / c.a
case .log3G10:
let c = Log3G10.self
if y < 0 { return y / c.g - c.c }
return (pow(10, y / c.a) - 1) / c.b - c.c
case .sLog3:
let c = SLog3.self
if y >= 171.2102946929 / 1023 {
return pow(10, (y * 1023 - 420) / 261.5) * 0.19 - 0.01
}
return (y * 1023 - 95) * c.linBreak / (171.2102946929 - 95)
}
}
// MARK: Constants
private enum LogC4 {
static let a: Float = (exp2(18) - 16) / 117.45
static let b: Float = (1023 - 95) / 1023
static let c: Float = 95.0 / 1023.0
static let s: Float = (7 * log(2.0 as Float) * exp2(7 - 14 * c / b)) / (a * b)
static let t: Float = (exp2(14 * (-c / b) + 6) - 64) / a
}
private enum Log3G10 {
static let a: Float = 0.224282
static let b: Float = 155.975327
static let c: Float = 0.01
static let g: Float = 15.1927
}
private enum SLog3 {
static let linBreak: Float = 0.01125000
}
}