Skip to content

Commit

Permalink
Merge pull request #264 from facelessuser/enhance/rec2100-hlg
Browse files Browse the repository at this point in the history
Add proper handling of gamma and black level lift
  • Loading branch information
facelessuser authored Jan 20, 2023
2 parents ff05131 + 8035ff1 commit df022a5
Showing 1 changed file with 50 additions and 10 deletions.
60 changes: 50 additions & 10 deletions coloraide/spaces/rec2100_hlg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,68 @@
from .srgb import sRGB
from .. import algebra as alg
from ..types import Vector
import math

A = 0.17883277
B = 0.28466892 # `1 - 4 * A`
C = 0.55991073 # `0.5 - A * alg.nlog(4 * A)`
# Sets 18% grey card to ~38% (37.7...) in order to set diffused white to 75%.
SCALE = 0.26496256042100724
INV_SCALE = 1 / SCALE


def hlg_oetf(values: Vector) -> Vector:
class Environment:
"""Class to calculate and contain any required environmental data."""

def __init__(
self,
lw: float,
lb: float,
scale: float
):
"""Initialize environmental data."""

self.a = 0.17883277
self.b = 0.28466892 # `1 - 4 * a`
self.c = 0.55991073 # `0.5 - a * alg.nlog(4 * a)`
self.beta = hlg_black_level_lift(lw, lb)
self.scale = scale
self.inv_scale = 1 / scale


def hlg_gamma(lw: float = 1000.0) -> float:
"""
Return the reference HLG system gamma.
Ranges should be `lw >= 1000 cd / m^2`.
"""

return 1.2 + 0.42 * math.log(lw / 1000.0)


def hlg_black_level_lift(lw: float = 0.0, lb: float = 1000.0) -> float:
"""
Return beta (the black level lift) using the nominal peak level luminance and display luminance for black.
Ranges should be `lw >= 1000 cd / m^2` and `lb <= 0.005 cd / m^2`.
"""

return math.sqrt(3 * (lb / lw) ** (1 / hlg_gamma(lw)))


def hlg_oetf(values: Vector, env: Environment) -> Vector:
"""HLG OETF."""

adjusted = [] # type: Vector
for e in values:
adjusted.append(alg.nth_root(3 * e, 2) if e <= 1 / 12 else A * alg.nlog(12 * e - B) + C)
e = alg.nth_root(3 * e, 2) if e <= 1 / 12 else env.a * alg.nlog(12 * e - env.b) + env.c
adjusted.append((e - env.beta) / (1 - env.beta))
return adjusted


def hlg_eotf(values: Vector) -> Vector:
def hlg_eotf(values: Vector, env: Environment) -> Vector:
"""HLG EOTF."""

adjusted = [] # type: Vector
for e in values:
adjusted.append((e ** 2) / 3 if e <= 0.5 else (alg.nexp((e - C) / A) + B) / 12)
e = (1 - env.beta) * e + env.beta
adjusted.append((e ** 2) / 3 if e <= 0.5 else (alg.nexp((e - env.c) / env.a) + env.b) / 12)
return adjusted


Expand All @@ -53,13 +92,14 @@ class Rec2100HLG(sRGB):
SERIALIZE = ('--rec2100-hlg',)
WHITE = WHITES['2deg']['D65']
DYNAMIC_RANGE = 'hdr'
ENV = Environment(1000, 0, SCALE)

def to_base(self, coords: Vector) -> Vector:
"""To base from Rec 2100 HLG."""

return alg.multiply(hlg_eotf(coords), INV_SCALE, dims=alg.D1_SC)
return [c * self.ENV.inv_scale for c in hlg_eotf(coords, self.ENV)]

def from_base(self, coords: Vector) -> Vector:
"""From base to Rec. 2100 HLG."""

return hlg_oetf(alg.multiply(coords, SCALE, dims=alg.D1_SC))
return hlg_oetf([c * self.ENV.scale for c in coords], self.ENV)

0 comments on commit df022a5

Please sign in to comment.