1. 소개
이 절은 규범적인 내용이 아닙니다.
CSS Color 4는 Open Web Platform에 와이드 컬러 개멋(WCG) 색 공간을 추가합니다. 설계상, 이들은 모두 표준 다이내믹 레인지(SDR) 색 공간입니다. 본 명세는 하이 다이내믹 레인지(HDR)를 지원하기 위한 추가사항을 정의합니다.

WCG 명세는 수십 년간 널리 안정적으로 존재해 왔지만, HDR 표준은 성숙하지 않았으며 최근 10년간 잦은 개정을 거쳤습니다.
1.1. 값 정의
이 명세는 CSS 속성 정의 규칙을 [CSS2]에서, 값 정의 구문을 [CSS-VALUES-3]에서 따릅니다. 이 명세에서 정의하지 않은 값 유형은 CSS Values & Units [CSS-VALUES-3]에서 정의합니다. 다른 CSS 모듈과 결합될 때 이러한 값 유형의 정의가 확장될 수 있습니다.
해당 정의에 명시된 속성별 값 외에도, 본 명세에서 정의된 모든 속성은 CSS 전역 키워드도 값으로 허용합니다. 가독성을 위해 반복 기재하지 않았습니다.
2. HDR 용어
2.1. 다이내믹 레인지 정의
다이내믹 레인지는 휘도가 가장 밝은 색과 가장 어두운 색 사이의 차이입니다. 다이내믹 레인지는 사진에서 스톱(stop) 단위로 측정합니다. 1스톱은 휘도의 2배 증가입니다.
function DynamicRange( high, low) { return Math. log2( high) - Math. log2( low); }
HDR 기준 백색 또는 미디어 화이트라고도 하며, 일반적인 흰색 배경이나 어두운 배경 위의 흰색 텍스트의 색상을 의미합니다. 이는 화면 전체에 걸쳐 편안하게 볼 수 있습니다.
표준 다이내믹 레인지 (SDR)에서, HDR 기준 백색은 가장 밝은 색이며, 최대 밝기의 빨강, 초록, 파랑으로 생성됩니다.
화면의 전체 밝기를 사용자의 취향이나 표준과 다른 시청 조건에 맞추어 조정하는 경우가 흔합니다.
SDR의 경우, 화면을 더 밝게 하더라도 다이내믹 레인지는 변하지 않습니다. 가장 어두운 색도 같이 밝아지기 때문입니다.
하이 다이내믹 레인지(HDR)에서는, HDR 기준 백색보다 더 밝은 색상을 표시할 수 있습니다. 예를 들어, HDR 디스플레이에서 HDR 기준 백색이 203 cd/m²로 설정된 경우, 작은 하이라이트를 1000 cd/m²까지 표시할 수 있습니다. 일반적으로 가장 밝은 색상은 디스플레이의 일부 영역에서만, 제한된 시간 동안 표시할 수 있습니다. 이는 에너지 사용과 발열 때문입니다.
HDR의 경우, 화면을 더 밝게 하면 다이내믹 레인지가 증가하며, HDR 기준 백색의 휘도는 변하지 않습니다.
로그 스케일의 SDR 및 HDR 다이내믹 레인지 다이어그램 추가 필요
§ 9 SDR과 HDR 콘텐츠 합성 및 색 공간 변환 시, SDR 콘텐츠의 HDR 기준 백색은 203 cd/m²에 고정해야 합니다. [Rpt_BT.2408] 참고 이를 통해 합성 입력 신호의 HDR 기준 백색 레벨이 결합 신호의 HDR 기준 백색 레벨과 일치하도록 합니다.
HDR(또는 SDR과 HDR 혼합) 콘텐츠를 표시할 때, 기준 마스터링 디스플레이보다 성능이 낮은 디스플레이이거나, 표준과 다른 시청 환경인 경우, 색상 재렌더링 단계(OOTF)가 수행됩니다. 이 경우 HDR 기준 백색이 203 cd/m²보다 낮거나 높게 표시될 수 있습니다.
2.2. 헤드룸 소개
HDR 디스플레이가 낼 수 있는 최대 휘도는 매우 다양합니다.
최대 백색이 HDR 기준 백색보다 얼마나 더 높은지의 정도를 HDR 헤드룸이라 하며, 이는 HDR 기준 백색의 수준, 사용자 기호, 시청 환경에 따라 달라집니다.
보통 사진의 스톱 단위로 표현합니다. 따라서 표준 다이내믹 레인지(SDR)는 정의상 HDR 헤드룸이 0스톱입니다. 가장 밝은 백색이 HDR 기준 백색이기 때문입니다.
암전 시청 환경에서 HDR 기준 백색을 100 cd/m2로 맞추면, HDR 헤드룸이 4스톱(16배)이 됩니다.
웹 플랫폼은 현재 디스플레이의 헤드룸 수준을 직접적으로 노출하지 않습니다. 시청 조건, 실시간 미계량 헤드룸 정보는 추적 벡터가 되기 때문입니다 (예: 사용자가 실외로 이동했거나 쾌청한 날씨임을 탐지하는 용도 등).
항상 사용 가능한 최대 HDR 헤드룸을 사용하는 것이 바람직하지 않을 수 있습니다. CSS는 대략적으로 얼마나 많은 헤드룸을 사용할지 제어하는 방법을 제공합니다. 이 값은 엘리먼트별, 시간별로 달라질 수 있습니다.
3. 다이내믹 레인지 제어
3.1. dynamic-range-limit 속성
| 이름(Name): | dynamic-range-limit |
|---|---|
| 값(Value): | standard | no-limit | constrained | <dynamic-range-limit-mix()> |
| 초깃값(Initial): | no-limit |
| 적용 대상(Applies to): | 모든 요소(all elements) |
| 상속 여부(Inherited): | 예(yes) |
| 백분율(Percentages): | 해당 없음(n/a) |
| 계산값(Computed value): | dynamic-range-limit 계산값 참고 |
| 정규 순서(Canonical order): | 문법에 따름(per grammar) |
| 애니메이션 유형(Animation type): | dynamic-range-limit-mix() 기준(by) |
테스트(Tests)
- standard
- 표시되는 가장 높은 휘도 색상이 HDR 기준 백색과 동일합니다. 즉, CSS 색상 white입니다.
- no-limit
- 표시되는 가장 높은 피크 휘도가 HDR 기준 백색보다 훨씬 더 큽니다. 즉, CSS 색상 white이지만 정확한 수준은 지정하지 않습니다.
- constrained
- 표시되는 가장 높은 피크 휘도가 HDR 기준 백색보다 다소 크며, 즉 CSS 색상 white이면서, SDR과 HDR 콘텐츠를 함께 편안하게 감상할 수 있도록 합니다.
3.2. 다이내믹 레인지 한계 혼합: dynamic-range-limit-mix() 함수
이 함수는 하나 이상의 dynamic-range-limit 값을 받아, 내부적으로 HDR 기준 백색 대비 스톱 단위 값으로 변환하고, 지정한 비율대로 혼합한 결과로 디스플레이를 조정합니다. 프라이버시(개인정보 보호) 상 계산된 실제 결과는 노출하지 않습니다.
dynamic-range-limit-mix() = dynamic-range-limit-mix( [ <'dynamic-range-limit'> && <percentage [0,100]> ]#{2,} )
테스트(Tests)
3.3. dynamic-range-limit의 계산값
지정한 값이 standard, constrained, no-limit일 경우, 계산값은 지정한 값과 동일합니다.
지정한 값이 dynamic-range-limit-mix()인 경우, 계산값은 아래 알고리즘에 의해 결정됩니다.
-
v1, ..., vN을 혼합할 파라미터들의 계산값으로 둡니다.
-
p1, ..., pN을 혼합 비율(백분율)로 두고, 합이 100%가 되도록 정규화합니다.
-
기여 백분율은 다음과 같이 정의합니다:
-
p1_standard,...,pN_standard를 v1,...,vN 중 standard의 비율로 둡니다.
-
p1_constrained_high,...,pN_constrained_high를 v1,...,vN 중 constrained의 비율로 둡니다.
-
p1_no_limit,...,pN_no_limit를 v1,...,vN 중 no-limit의 비율로 둡니다.
-
-
가중합은 아래와 같이 계산합니다:
-
p_standard=(p1_standard*p1+...+pN_standard*pN)/100
-
p_constrained_high=(p1_constrained_high*p1+...+pN_constrained_high*pN)/100
-
p_no_limit=(p1_no_limit*p1+...+pN_no_limit*pN)/100
-
-
p_standard, p_constrained_high, p_no_limit 중 하나라도 100%라면, 계산값은 각각 standard, constrained, no-limit입니다.
-
그렇지 않으면 계산값은 dynamic-range-limit-mix()로, 파라미터는 standard, constrained, no-limit 순서 및 비율 p_standard, p_constrained_high, p_no_limit로 하며, 비율이 0%인 파라미터는 생략합니다. 모든 파라미터가 생략되면, 계산값은 초깃값(initial value)입니다.
테스트(Tests)
dynamic-range-limit-mix ( high10 % , dynamic-range-limit-mix ( standard25 % , constrained75 % ) 20 % , dynamic-range-limit-mix ( constrained10 % , no-limit30 % ) 20 % )
는 아래와 같습니다.
dynamic-range-limit-mix ( standard10 % , constrained40 % , no-limit50 % )
4. <color> 구문
이 모듈은 <color-function> 타입을 확장합니다:
<color-function> = <rgb()> | <rgba()> |
<hsl()> | <hsla()> | <hwb()> |
<lab()> | <lch()> | <oklab()> | <oklch()> |
<ictcp()> | <jzazbz()> | <jzczhz()> |
<alpha()> |
<color()>
ictcp() = ictcp([from <color>]?
[<percentage> | <number> | none]
[<percentage> | <number> | none]
[<percentage> | <number> | none]
[ / [<alpha-value> | none] ]? )
jzazbz() = jzazbz([from <color>]?
[<percentage> | <number> | none]
[<percentage> | <number> | none]
[<percentage> | <number> | none]
[ / [<alpha-value> | none] ]? )
jzczhz() = jzczhz([from <color>]?
[<percentage> | <number> | none]
[<percentage> | <number> | none]
[<hue> | none]
[ / [<alpha-value> | none] ]? )
5. 헤드룸을 파라미터로 하는 HDR 색상: hdr-color() 함수
hdr-color() 함수는 HDR 헤드룸에 따라 값이 자동 계산되는 색상 범위를 지정할 수 있게 합니다.
이 함수는 두 개의 <color> 값을 지정하며, 각각에 대응하는 HDR 헤드룸 레벨이 있습니다. (두 헤드룸 값은 동일할 수 없습니다). 실제 값은 현재 HDR 헤드룸 값에 기반해 두 색상을 보간하여 계산됩니다. 자세한 내용은 § 5.1 헤드룸 기준 색상 보간에서 설명합니다.
개인정보 보호상의 이유로, 실제로 계산된 색상이나 HDR 헤드룸 값은 드러나지 않습니다. 이것이 지문 추적 벡터가 될 수 있기 때문입니다.
구문은 다음과 같습니다:
hdr-color() = color-hdr([ <color> && <number [0,∞]>? ]#{2})
color-hdr ( color ( rec2100-linear0.9 1.0 0.8 ) 0 , color ( rec2100-linear1.8 2.0 1.5 ) 2 );
HDR 헤드룸 <= 0인, 즉 SDR 디스플레이에서는 이 색상은
color ( rec2100-linear0.9 1.0 0.8 )
HDR 헤드룸가 2 이상인 디스플레이에서는 이 색상은
color ( rec2100-linear1.8 2.0 1.5 ) 2 );
헤드룸이 0과 2 사이인 디스플레이에서는 색상이 보간됩니다. 예시로, 헤드룸이 1일 때:
X = 243.664, Y = 275.713, Z = 244.000
색상은 절대 D65 CIE XYZ로 보간됩니다.
이는 xyz-d65에서 각 색상 성분에 203 [Rpt_BT.2408]을 곱하여, 상대 단위(Y가 1, 실제 밝기와 무관함)를 절대 단위(cd/m², "니트"라고도 함)로 변환합니다. 샘플 코드에서는 이 상수를 Yw (HDR 기준 백색의 휘도)로 나타냅니다.
5.1. 헤드룸 기준 색상 보간
헤드룸 H1에서의 색상 c1과 헤드룸 H2에서의 색상 c2 사이를 보간하여, 대상 헤드룸이 H일 때 결과 색상 cxyz를 얻으려면:
-
c1xyz를 c1을 절대 D65 CIE XYZ로 변환한 값으로 둡니다.
-
c2xyz를 c2를 절대 D65 CIE XYZ로 변환한 값으로 둡니다.
-
w1 = clamp((H - H2) / (H1 - H2), 0, 1)
-
w2 = clamp((H - H1) / (H2 - H1), 0, 1) w2 = 1 - w1임에 유의하십시오.
-
eps = 0.001로 둡니다.
-
cxyz = Array(3)로 둡니다.
-
i를 0부터 2까지 반복하며: cxyz[i] = pow(c1xyz[i] + eps, w1 ) * pow(c2xyz[i] + eps, w2 ) - eps
참고: eps는 0으로 나누는 경우를 방지하며, SDR 색상과 같이 검정에 가까운 색을 보간할 때 특히 중요합니다.
c1xyz =[ 173.156 , 195.260 , 178.003 ] c2xyz =[ 342.883 , 389.315 , 334.467 ] w1 =0.5 w2 =0.5 cxyz =[ 243.664 , 275.713 , 244.000 ]
c1xyz =[ 156.285 , 188.337 , 28.015 ] c2xyz =[ 3776.1434 , 4362.407 , 1577.913 ] w1 =0.571 w2 =0.429 cxyz =[ 611.911 , 724.180 , 157.650 ]
c1은 헤드룸 값이 0.5 이하일 때는 변형되지 않고 사용되며, c2는 헤드룸 값이 4 이상일 때 변형 없이 사용됩니다.
6. 디바이스 독립적 HDR 색상
CSS Color 4 § 9 디바이스 독립 색상: CIE Lab, LCH, Oklab, OKLCh가 디바이스 독립 SDR 색상을 지정하는 것과 마찬가지로, 본 명세는 디바이스 독립 HDR 색상 지정도 허용합니다.
6.1. ICtCp 소개
이 절은 규범적인 내용이 아닙니다.
ICTCP 색 공간은 CIE Lab보다 지각적 균일성이 뛰어나며, 비디오 및 디지털 사진 시스템의 색상 이미지 파이프라인에서, 하이 다이내믹 레인지(HDR) 및 와이드 컬러 개멋(WCG) 이미지를 위해 사용됩니다.
T와 P 인덱스는 인간 시각계에서 트리타노프(노랑-파랑) 축과 프로타노프(빨강-초록) 반대 색 축을 의미합니다. 보통 인덱스 없이 ICtCp로 표기합니다.
ICTCP는 Dolby Laboratories에서 [What_is_ICtCp] 처음 개발하였으며, Ebner와 Fairchild의 IPT 색 공간 [Development_ITP]에서 비롯되었습니다. 이는 [Rec_BT.2100]에서 Constant Intensity ICTCP 신호 포맷으로 정의됩니다. YCbCr을 대체하기 위해 고안되었습니다 [Perrin].
이는 인간 시각계의 LMS 원추체 원색 기반이며; Hunt-Pointer-Estevez(HPE) XYZ→LMS 변환이 쓰입니다. D65 화이트포인트에 정규화됩니다. 그런 다음 4% 크로스토크 행렬을 적용하여 [What_is_ICtCp], BT.2020 RGB의 가멋 헐 오목 현상을 줄이고, 보간 오류를 최소화합니다. 크로스토크는 일정한 색상의 선과 Just Noticeable Difference(JND) MacAdam 타원의 균일성을 향상시킵니다.
Lab이 저휘도 반사 색상 기준으로 테스트된 반면, ICTCP는 고채도(WCG), 자발광, 고휘도(HDR) 색상에도 검증되었습니다.
이로써 HDR 색상 차이 측정 (deltaE ITP)와 SDR/HDR 혼합 컬러 검출에 적합합니다.
아주 넓은 가멋의 원색 빨강 예시:
color ( rec2100-pq0.58 0 0 ) /* ictcp(44.6% -0.129 0.399) */ color ( rec20201 0 0 ) /* ictcp(44.7% -0.130 0.399) */
이 두 색상은 ICTCP 상 매우 가깝고 deltaE ITP는 0.487이므로 시각적 차이가 없습니다.
이들은 sRGB "red"와는 매우 다르게 나타납니다:
color ( rec2100-pq0.58 0 0 ) /* ictcp(44.6% -0.129 0.399) */ red/* ictcp(42.8% -0.116 0.279) */
deltaE ITP는 87.7로, 색상 차이는 매우 큽니다.
6.2. Jzazbz 및 JzCzhz 소개
이 절은 규범적인 내용이 아닙니다.
Jzazbz 색 공간 [Safdar-PUCS]과 극좌표형 JzCzhz는, BT.2020과 같은 넓은 가멋, 다양한 휘도, HDR 색상을 정확하게 표현하기 위해 설계되었습니다. 지각적 속성(명도, 채도, 색상) 간 상호 의존성을 최소화하였으며, 특히 CAM16-UCS보다 우수한 색상 균일성을 가집니다.
CIE Lab은 [0%, 100%] 범위의 명도 축을 HDR 기준 백색에 상대적으로 사용하고; Oklab도 [0, 1.0] 범위의 명도 축을 사용하지만, 1.0은 HDR 기준 백색을 의미합니다. 반면 Jzazbz의 Jz축([0, 1.0])은 Perceptual Quantizer와 유사 인코딩을 사용, 13스톱 이상의 다이내믹 레인지도 표현합니다.
6.3. ICtCp
ICtCp 색 공간은 세 개의 숫자형 인자를 받으며, I는 명도(라이트니스, Lab의 L과 유사해도 휘도 범위가 10,000 cd/m2까지)에 해당하고 CT, CP는 노랑-파랑(트리타노프) 및 빨강-초록(프로타노프) 반대축(Lab의 b, a와 유사)에 해당합니다.
특성은 다음과 같습니다:
| x | y | |
| 화이트 색도 | D65 | |
|---|---|---|
| 전달 함수 | Perceptual Quantizer | |
| 화이트 휘도 | 203 cd/m² | |
| 최고 화이트 휘도 | 10,000 cd/m² | |
| 블랙 휘도 | 0.001 cd/m² | |
| 이미지 상태 | display-referred | |
| 백분율 표시 | I, Ct, Cp 모두 허용 | |
| 백분율 참조 범위 | I는 0% = 0.0, 100% = 1.0 Ct, Cp는 -100% = -0.5, 100% = 0.5 | |
[Rec_BT.2100]에서는 ICTCP를 linear-light BT.2100 RGB [Rec_BT.2100]에서 변환하도록 정의하지만, 실제로는 LMS 경유를 거치며, 따라서 어떤 색 공간도 XYZ→LMS 변환을 거치면 표현할 수 있습니다. [What_is_ICtCp] 참조. 샘플 코드에서도 이 방식을 씁니다.
ictcp(0.58069 0 0)
상대 색상 구문에서 ictcp() 함수의 허용 성분 키워드는 다음과 같습니다:
-
i는 <number>이며, 원본 색상의 I(명도/라이트니스)를 나타냅니다. 변환이 필요한 경우 변환 후 ictcp로 계산됩니다. 1.0은 100%와 같습니다.
-
ct 및 cp는 <number>이며, 원본 색상의 ct, cp 축을 나타냅니다. 변환이 필요한 경우 변환 후 ictcp로 계산됩니다. 0.5는 100%와 같고, -0.5는 -100%와 같습니다.
-
alpha는 <number>이며, 원본 색상의 알파(투명도) 성분에 해당합니다. 1.0은 100%와 같습니다.
6.4. Jzazbz
Jzazbz 색 공간은 세 개의 숫자형 인자를 받으며, Jz는 명도(라이트니스, Lab의 L과 유사)에 해당하고 az와 bz는 빨강-초록과 노랑-파랑의 반대 색 축을 나타냅니다(Lab의 a, b와 유사).
Jzazbz는 다음과 같은 특성을 가집니다:
| x | y | |
| 화이트 색도 | D65 | |
|---|---|---|
| 전달 함수 | Perceptual Quantizer | |
| 최고 화이트 휘도 | 10,000 cd/m² | |
| 블랙 휘도 | 0.001 cd/m² | |
| 이미지 상태 | display-referred | |
| 백분율 | Jz, az, bz에 허용 | |
| 백분율 참조 범위 | Jz: 0% = 0.0, 100% = 1.0 az, bz: -100% = -0.21, 100% = 0.21 | |
Lab과 달리 D65 화이트포인트가 사용된다는 점에 유의하세요. 따라서 대부분의 RGB 색 공간(D65 화이트포인트 사용)에서는 색도 적응 단계가 필요하지 않습니다.
XYZ-D65와 Jzazbz 간 변환을 위한 샘플 코드가 제공됩니다.
jzazbz(0.22207 -0.00016 -0.00012)
상대 색상 구문에서 jzazbz() 함수의 허용 컴포넌트 키워드는 아래와 같습니다:
-
j는 <number>로, 원본 색상의 Jz(명도) 성분이며, 변환 필요 시 jzazbz로 변환 후의 값입니다. 1.0은 100%와 동일합니다.
-
a 및 b는 <number>이며, 원본 색상의 az, bz 축에 해당하며, 변환 필요 시 jzazbz로 변환 후의 값입니다. 0.21은 100%, -0.21은 -100%와 동일합니다.
6.5. JzCzhz
LCH가 Lab의 극좌표 표현인 것처럼, JzCzhz도 Jzazbz의 극좌표형입니다.
Jz는 Jzazbz의 값과 동일하며, 명도를 나타냅니다. Cz는 크로마(색진함, 선명함), hz는 색상 각도(양의 az축에서 양의 bz축 방향)입니다.
특성은 다음과 같습니다:
| x | y | |
| 화이트 색도 | D65 | |
|---|---|---|
| 전달 함수 | Perceptual Quantizer | |
| 최고 화이트 휘도 | 10,000 cd/m² | |
| 블랙 휘도 | 0.001 cd/m² | |
| 이미지 상태 | display-referred | |
| 백분율 표시 | Jz, Cz에 허용 | |
| 백분율 참조 범위 | Jz: 0% = 0.0, 100% = 1.0 Cz: 0% = 0.0, 100% = 0.26 | |
| 무채색 hue ε | Cz <= 0.0000026 | |
jzazbz(0.17542 -0.1179 0.1092)
그리고 아래는 같은 색상의 극좌표 표현입니다.
jzczhz(0.17542 0.1614 132.50)
상대 색상 구문에서 jzczhz() 함수의 허용 컴포넌트 키워드는 아래와 같습니다:
-
j는 <number>로, 원본 색상의 Jz(명도) 성분입니다. 변환 필요 시 jzczhz로 변환 후의 값입니다. 100은 100%에 해당합니다.
-
c는 <number>로, 원본 색상의 Cz(크로마, 채도) 성분입니다. 변환 필요 시 jzczhz로 변환 후의 값입니다. 0.26은 100%에 해당합니다.
-
h는 <number>로, 원본 색상의 hz(색상), deg 단위이며, 변환 필요 시 jzczhz로 변환 후의 값입니다. [0, 360] 범위로 정규화합니다. 90은 90deg입니다.
6.5.1. Jzazbz 색상을 JzCzhz 색상으로 변환
JzCzhz로의 변환은 단순합니다:
- hz = atan2(bz, az) // 단, 각도로 변환해야 함!
- Cz = sqrt(az^2 + bz^2)
- Jz는 동일
실제 코드에서는 Cz가 ε보다 작으면 none 값을 반환해야 합니다.
6.5.2. JzCzhz 색상을 Jzazbz 색상으로 변환
Jzazbz로의 변환도 단순합니다:
- az = Cz cos(H) // 먼저 라디안으로 변환!
- bz = Cz sin(H) // 먼저 라디안으로 변환!
- Jz는 동일
실제 코드에서는 hz가 none인 값을 확인해야 합니다.
7. 사전 정의 및 사용자 지정 색 공간 지정: color() 함수
color() 함수는 특정 색 공간 내에서 색상을 지정할 수 있게 합니다(대부분의 다른 컬러 함수가 암묵적으로 sRGB 색 공간에 기반하는 것과 다름).
이 명세는 color() 함수를 HDR용 사전 정의 색 공간에도 쓸 수 있도록 확장하며, CSS Color 4 § 10. 사전 정의 색 공간의 SDR용 사전 정의 공간, CSS Color 5 § 4 상대 색상 구문도 지원합니다.
구문은 이제 다음과 같습니다:
<predefined-rgb> = srgb | srgb-linear | display-p3 | display-p3-linear | a98-rgb | prophoto-rgb | rec2020 | rec2100-pq | rec2100-hlg | rec2100-linear
8. HDR용 사전 정의 색 공간:
CSS Color 4에서 정의한 SDR 색 공간 외에도, 다음 HDR 색 공간들이 color 함수에서 사용될 수 있도록 정의되어 있습니다.
이러한 새로운 색 공간에서 값의 직렬화 방법은 CSS Color 4 § 15. <color> 값 직렬화에 설명된 내용과 동일합니다.
8.1. rec2100-pq
rec2100-pq [Rec_BT.2100] 색 공간은 세 개의 숫자 파라미터(빨강, 초록, 파랑 채널)를 받으며, 각각의 유효 범위는 실제 비트 깊이(10 또는 12비트)에 관계없이 [0, 1]입니다.
Perceptual Quantizer(PQ) 전기-광 전달 함수가 사용됩니다 [SMPTE-ST-2084],[Rec_BT.2100]. PQ는 화면 주변 밝기가 5 cd/m²인 기준 시청 조건을 가정합니다.
ITU Reference 2100은 HDR 4k 및 8k 텔레비전에 사용됩니다.
주요 특성: (디스플레이 원색은 [Rec.2020]과 동일):
| x | y | |
| 빨강 색도 | 0.708 | 0.292 |
|---|---|---|
| 초록 색도 | 0.170 | 0.797 |
| 파랑 색도 | 0.131 | 0.046 |
| 화이트 색도 | D65 | |
| 전달 함수 | Perceptual Quantizer | |
| 화이트 휘도 | 203 cd/m² | |
| 최고 화이트 휘도 | 10,000 cd/m² | |
| 블랙 휘도 | ≤ 0.005 cd/m² | |
| 이미지 상태 | display-referred | |
| 백분율 | R, G, B에 허용 | |
| 백분율 참조 범위 | R,G,B: 0% = 0.0, 100% = 1.0 | |
비기준 시청 환경의 협대역 PQ 비디오 또는 어떤 환경이든 HLG의 경우, 블랙 레벨은 [Rec_BT.814] 부록에 지정된 PLUGE 테스트 신호와 절차를 사용하여 조정해야 합니다. CSS에서 사용되는 PQ 값(광대역)은 블랙이 코드값 0에 해당합니다.
color(rec2100-pq 1.0 1.0 1.0);
color(rec2100-pq 0.58 0.58 0.58);
아래 색상은 사진작가의 "18% 반사 회색" 카드와 같은 중간 회색(휘도 17 cd/m²)입니다.
color(rec2100-pq 0.34 0.34 0.34)
sRGB 및 P3의 빨강, 초록, 파랑 엔코딩 등 다른 예시 추가 필요
선형광 RGB 신호는 PQ로 다음과 같이 변환됩니다. PQ에서 최대 인코딩값(피크, 소면적 화이트)은 10,000 cd/m²이며, HDR 기준 백색은 203 cd/m² [Rpt_BT.2408]입니다.
var Er; // 빨강, 초록 또는 파랑 성분, [0, 1] (SDR), [0, 70대] (HDR) var Yw= 203 ; // diffuse white의 휘도, cd/m² var x= Er* Yw/ 10000 ; // 피크 화이트의 휘도는 10,000 cd/m² const n= 2610 / ( 2 ** 14 ); const m= 2523 / ( 2 ** 5 ); const c1= 3424 / ( 2 ** 12 ); const c2= 2413 / ( 2 ** 7 ); const c3= 2392 / ( 2 ** 7 ); xPQ= ((( c1+ ( c2* ( x** n))) / ( 1 + ( c3* ( x** n)))) ** m);
xPQ는 "감마 보정"(OETF 적용) 신호 [0, 1]입니다.
PQ 인코딩 값을 다시 선형광으로 변환하는 방법은 다음과 같습니다:
var xPQ; // 빨강, 초록 또는 파랑 PQ 인코딩 성분, [0, 1] const ninv= ( 2 ** 14 ) / 2610 ; const minv= ( 2 ** 5 ) / 2523 ; const c1= 3424 / ( 2 ** 12 ); const c2= 2413 / ( 2 ** 7 ); const c3= 2392 / ( 2 ** 7 ); var x= ((( Math. max((( xPQ** minv) - c1), 0 ) / ( c2- ( c3* ( xPQ** minv)))) ** ninv); var Yw= 203 ; // diffuse white의 휘도, cd/m² var Ea= x* 10000 ; // 휘도, [0, 10,000] var Er= x* 10000 / Yw; // diffuse white 대비 휘도, [0, 70대]
8.2. rec2100-hlg
rec2100-hlg [Rec_BT.2100] 색 공간은 빨강, 초록, 파랑 채널별로 세 개의 숫자 인자를 받으며, 각 성분의 유효 범위는 실제 비트 깊이(10 또는 12비트)와 상관없이 [0, 1]입니다.
Hybrid Log-Gamma (HLG) 전기-광 전달 함수가 사용됩니다 [ARIB_STD-B67],[Rec_BT.2100]. HLG는 다양한 밝기의 디스플레이 및 시청 환경에서 사용자 밝기 제어와 함께 사용할 수 있습니다. 값 0.75가 "diffuse" 또는 "media" 화이트를 나타내며, "18% 반사 회색" 카드는 0.38 값입니다. [Rec_BT.2390].
주요 특성: (디스플레이 원색은 [Rec.2020]과 동일):
| x | y | |
| 빨강 색도 | 0.708 | 0.292 |
|---|---|---|
| 초록 색도 | 0.170 | 0.797 |
| 파랑 색도 | 0.131 | 0.046 |
| 화이트 색도 | D65 | |
| 전달 함수 | Hybrid Log-Gamma | |
| 화이트 휘도 | 시청 조건에 따라 다름 | |
| 피크 화이트 휘도 | 참조 화이트의 12배 | |
| 블랙 휘도 | 참조 화이트에 따라 다름(본문 참고) | |
| 이미지 상태 | scene-referred | |
| 백분율 | R, G, B에 허용 | |
| 백분율 참조 범위 | R,G,B: 0% = 0.0, 100% = 1.0 | |
어떤 시청 환경에서든 HLG 협대역 비디오의 경우, 블랙 레벨은 [Rec_BT.814] 부록 4의 PLUGE 테스트 신호와 절차로 조정해야 합니다.
CSS에서 사용하는 HLG 값(광대역)은 블랙이 코드값 0과 일치합니다.
color(rec2100-hlg 0.75 0.75 0.75);
아래 색상은 26~104 cd/m²의 중간 회색입니다.
color(rec2100-hlg 0.38 0.38 0.38)
선형광 RGB 신호는 아래와 같이 HLG로 변환됩니다 [Rec_BT.2390]:
var E; // 빨강, 초록, 파랑 성분, [0, 1] const a= 0.17883277 ; const b= 0.28466892 ; // 1 - (4 * a) const c= 0.55991073 ; // 0.5 - a * Math.log(4 *a) // 음수 처리 var sign= E< 0 ? - 1 : 1 ; var abs= Math. abs( E); if ( abs<= 1 / 12 ) { Edash= sign* Math. sqrt( 3 * abs); } else { Edash= a* Math. log( 12 * E- b) + c; }
Edash는 "감마 보정"(OETF 적용) 신호입니다.
역변환(HLG 인코딩에서 선형광으로)은 아래와 같습니다 [Rec_BT.2390]::
var Edash; // 빨강, 초록, 파랑 인코딩 성분, [0, 1] const a= 0.17883277 ; const b= 0.28466892 ; // 1 - (4 * a) const c= 0.55991073 ; // 0.5 - a * Math.log(4 *a) if ( Edash<= 0.5 ) { E= ( Edash** 2 ) / 3 ; } else { E= ( Math. exp(( Edash- c) / a) + b) / 12 ; }
본문에 정의된 black level lift Β 추가?
8.3. rec2100-linear
rec2100-linear [Rec_BT.2100] 색 공간은 빨강, 초록, 파랑 채널에 해당하는 세 개의 숫자 인자를 받으며, 각 성분의 공칭 범위는 실제 비트 깊이(10 또는 12비트)에 상관없이 [0, 1]입니다.
빨강, 초록, 파랑이 모두 1.0인 색상은 휘도 203 cd/m²의 HDR 기준 백색을 나타냅니다.
color ( rec2100-linear1 1 1 )
color ( rec2100-linear9.852 9.852 9.852 )
휘도 9.852 × 203 = 1,999 cd/m²의 화이트 하이라이트를 나타냅니다.
color(rec2100-linear 1 1 1)
선형광 전기-광 전달 함수가 사용됩니다.
주요 특성: (디스플레이 원색은 [Rec.2020]과 동일):
| x | y | |
| 빨강 색도 | 0.708 | 0.292 |
|---|---|---|
| 초록 색도 | 0.170 | 0.797 |
| 파랑 색도 | 0.131 | 0.046 |
| 화이트 색도 | D65 | |
| 전달 함수 | Linear | |
| 화이트 휘도 | 203 cd/m² | |
| 피크 화이트 휘도 | 10,000 cd/m² | |
| 블랙 휘도 | 0.001 cd/m² | |
| 이미지 상태 | display-referred | |
| 백분율 | R, G, B에 허용 | |
| 백분율 참조 범위 | R,G,B: 0% = 0.0, 100% = 1.0 | |
9. SDR 및 HDR 콘텐츠 혼합
혼합은 CIE XYZ에서 수행하는 것이 좋으며, 이는 가멋 제한이 없는 선형광 공간입니다. 구현체는 선형광 RGB 공간에서도 혼합할 수 있으며, 이 경우 가멋 밖의 값(음수, 100% 초과 등)도 장치 색 공간으로 최종 전송 전까지는 잘리지 않거나 가멋 매핑되지 않도록 올바르게 처리해야 동일한 결과를 얻을 수 있습니다.
HLG 전달함수를 사용하는 HDR의 경우, SDR HDR 기준 백색은 75% HLG 값과 동일한 휘도에 맞춰야 합니다. [SMPTE-ST-2084]
자세한 내용은 ITU Rpt_BT.2408-0의 표 3, 4 [Rpt_BT.2408]도 참고하십시오.
PQ 전달함수를 사용하는 HDR의 경우, SDR HDR 기준 백색은 203 cd/m²(58% PQ 값의 휘도)로 맞춰야 합니다. [SMPTE-ST-2084].
단, 구현체가 비기준 시청 조건을 반영하기 위해 색상 재렌더링 단계(color re-rendering)를 포함할 수 있습니다.
10. <color> 값 직렬화
10.1. color() 함수 값 직렬화
이 절은 CSS Color 4 § 15.5 color() 함수 값 직렬화를 확장합니다.
color() 값의 직렬화형은 계산값을 바탕으로, 함수명과 색상 공간명을 color() 형식 및 ASCII 소문자로 씁니다.
성분 값은 10진수로 직렬화되며, <number>로 표기합니다. 각 성분 값 사이, 그리고 색상 공간명과 첫 색상 성분 사이에는 반드시 하나의 ASCII 공백 문자(" ")를 구분자로 사용합니다.
사전 정의된 HDR 색 공간의 경우, 왕복 변환(round-tripping)이 보장되는 최소 정밀도는 아래 표와 같습니다:
| HDR 색 공간 | 최소 비트수 |
|---|---|
| rec2100-pq, rec2100-hlg | 10 |
| rec2100-linear, jzazbz, jzczhz, ictcp | 16 |
(내부 저장 시 각 성분별 16bit, half-float 또는 float를 권장합니다). 값은 +∞ 방향 반올림 되어야 하며, 잘려(truncate)서는 안 됩니다.
11. 색상 변환 샘플 코드
이 절은 규범적인 내용이 아닙니다.
Tests
이 절은 규범적인 내용이 아니며, 테스트가 필요하지 않습니다.
가독성을 위해 행렬 곱셈에는 라이브러리를 사용합니다. (모든 곱셈과 덧셈을 인라인으로 작성하는 것보다 더 읽기 쉽습니다). 행렬은 column-major order입니다.
또한 이 코드는 CSS Color 4 § 18. 색상 변환 샘플 코드의 모든 변환 코드가 사용 가능하다고 가정합니다.
Jzazbz에서 사용하는 LMS는 ICtCp에서 사용하는 것과 동일하지 않으므로, 올바른 것을 사용하도록 주의하십시오!
11.1. rec2100-linear 샘플 코드
BT.2020과 BT.2100 색 공간은 동일한 RGB 원색과 화이트 포인트를 사용하며, 둘 모두 HDR 기준 백색을 성분 값 1.0에 둡니다.
// 이 함수들은 CSS Color 4의 색상 변환 함수를 사용합니다 function XYZ_to_lin_2100( XYZ) { // D65 XYZ 배열을 선형광 BT.2100 RGB로 변환 // [0,0,0]은 블랙, [1,1,1]은 미디어 화이트 // 1보다 큰 성분 값은 HDR 색을 의미 return XYZ_to_lin_2020( XYZ); } function lin_2100_to_XYZ( RGB) { // 선형광 BT.2100 RGB 배열을 // D65 XYZ로 변환 return lin_2020_to_XYZ( RGB); }
11.2. rec2100-pq 샘플 코드
function XYZ_to_pq_2100( XYZ) { // D65 XYZ 배열을 PQ 인코딩된 BT.2100 RGB로 변환 // [0,0,0]은 블랙, [1,1,1]은 10,000 cd/m^2의 화이트 // 미디어 화이트는 [0.5807,0.5807,0.5807] (유효 숫자 4자리) let linRGB= XYZ_to_lin_2100( XYZ); return pq_encode( linRGB); } function pq_2100_to_XYZ( RGB) { // PQ 인코딩된 BT.2100 RGB 배열을 // D65 XYZ로 변환 let linRGB= pq_decode( RGB); return lin_2100_to_XYZ( linRGB); } function pq_encode( RGB) { const Yw= 203 ; // 미디어 화이트의 절대 휘도, cd/m² const n= 2610 / ( 2 ** 14 ); const m= 2523 / ( 2 ** 5 ); const c1= 3424 / ( 2 ** 12 ); const c2= 2413 / ( 2 ** 7 ); const c3= 2392 / ( 2 ** 7 ); // [0, 1] 범위의 PQ 인코딩 성분을 받아 // 미디어 화이트 기준의 선형광을 반환 return RGB. map( function ( val) { let x= Math. max( val* Yw/ 10000 , 0 ); // 피크 화이트의 절대 휘도는 10,000 cd/m² let num= ( c1+ ( c2* ( x** n))); let denom= ( 1 + ( c3* ( x** n))); return (( num/ denom) ** m); }); } function pq_decode( RGB) { const Yw= 203 ; // 미디어 화이트의 절대 휘도, cd/m² const ninv= ( 2 ** 14 ) / 2610 ; const minv= ( 2 ** 5 ) / 2523 ; const c1= 3424 / ( 2 ** 12 ); const c2= 2413 / ( 2 ** 7 ); const c3= 2392 / ( 2 ** 7 ); // [0, 1] 범위의 PQ 인코딩 성분을 받아 // 미디어 화이트 기준의 선형광을 반환 return RGB. map( function ( val) { let x= (( Math. max((( val** minv) - c1), 0 ) / ( c2- ( c3* ( val** minv)))) ** ninv); return ( x* 10000 / Yw); // 미디어 화이트 대비 휘도, 대략 [0, 70] }); }
11.3. rec2100-hlg 샘플 코드
function XYZ_to_hlg_2100( XYZ) { // D65 XYZ 배열을 HLG 인코딩 BT.2100 RGB로 변환 // [0,0,0]은 블랙, [0.75,0.75,0.75]는 미디어 화이트 let linRGB= XYZ_to_lin_2100( XYZ); return hlg_encode( linRGB); } function hlg_2100_to_XYZ( RGB) { // PQ 인코딩 BT.2100 RGB 배열을 // D65 XYZ로 변환 let linRGB= hlg_decode( RGB); return lin_2100_to_XYZ( linRGB); } function hlg_encode( RGB) { const a= 0.17883277 ; const b= 0.28466892 ; // 1 - (4 * a) const c= 0.55991073 ; // 0.5 - a * Math.log(4 *a) const scale= 3.7743 ; // 18% 그레이를 HLG 0.38에, 미디어 화이트를 0.75에 배치 return RGB. map( function ( val) { // 먼저 선형광 미디어 화이트가 1/3이 되도록 스케일 val/= scale; // HLG OETF // ITU-R BT.2390-10 p.23 // 6.1 The hybrid log-gamma opto-electronic transfer function (OETF) if ( val<= 1 / 12 ) { return spow( 3 * val, 0.5 ); } return a* Math. log( 12 * val- b) + c; }); } function hlg_decode( RGB) { const a= 0.17883277 ; const b= 0.28466892 ; // 1 - (4 * a) const c= 0.55991073 ; // 0.5 - a * Math.log(4 *a) const scale= 3.7743 ; // 18% 그레이를 HLG 0.38에, 미디어 화이트를 0.75에 배치 return RGB. map( function ( val) { // 먼저 HLG EOTF // ITU-R BT.2390-10 p.30 // 6.3 The hybrid log-gamma electro-optical transfer function (EOTF) // 그 다음 3을 곱해 미디어 화이트를 1.0으로 if ( val<= 0.5 ) { return ( val** 2 ) / 3 * scale; } return (( Math. exp(( val- c) / a) + b) / 12 ) * scale; }); } function spow( base, exp) { let sign= base< 0 ? - 1 : 1 ; return sign* ( Math. abs( base) ** exp); }
11.4. jzazbz 샘플 코드
위에서 정의한 동일한 부호 지수 함수(spow)를 사용합니다.
function XYZ_to_Jzazbz( XYZ) { // D65 XYZ 배열을 JzAzBz로 변환 // [0,0,0]은 블랙이고, // 미디어 화이트는 [0.2220, -0.00016, -0.0001] const Yw= 203 ; // 미디어 화이트의 절대 휘도 const M= [ [ 0.41478972 , 0.579999 , 0.0146480 ], [ - 0.2015100 , 1.120649 , 0.0531008 ], [ - 0.0166008 , 0.264800 , 0.6684799 ], ]; const b= 1.15 ; const g= 0.66 ; // 먼저 XYZ를 미디어 화이트 상대가 아닌 절대값으로 // PQ의 최대 휘도는 10,000 cd/m² // BT.2048: 미디어 화이트 Y=203 cd/m² let [ Xa, Ya, Za] = XYZ. map( v=> v* Yw); // 파란색 곡률 최소화를 위해 X, Y 보정 let Xm= b* Xa- ( b- 1 ) * Za; let Ym= g* Ya- ( g- 1 ) * Xa; // LMS 원추체 도메인으로 이동 let LMS= multiplyMatrices( M, [ Xm, Ym, Za]); return LMStoJzazbz( LMS); } function LMStoJzazbz( LMS) { const M= [ [ 0.5 , 0.5 , 0 ], [ 3.524000 , - 4.066708 , 0.542708 ], [ 0.199076 , 1.096799 , - 1.295875 ], ]; const c1= 3424 / 2 ** 12 ; const c2= 2413 / 2 ** 7 ); const c3= 2392 / 2 ** 7 ; const n= 2610 / 2 ** 14 ; const p= ( 1.7 * 2523 ) / 2 ** 5 ; // 일반 PQ 대비 1.7 스케일 const d= - 0.56 ; const d0= 1.6295499532821566e-11 ; // 블랙을 0으로 되돌리기 위한 미세 오프셋 // LMS를 PQ 인코딩 let PQLMS= ( LMS. map( function ( val) { let num= c1+ c2* spow(( val/ 10000 ), n); let denom= 1 + c3* spow(( val/ 10000 ), n); return spow(( num/ denom), p); }) ); // Iz, az, bz 계산 let [ Iz, az, bz] = multiplyMatrices( M, PQLMS); // Iz에서 Jz 계산 let Jz= (( 1 + d) * Iz) / ( 1 + d* Iz) - d0; return [ Jz, az, bz]; } function Jzazbz_to_XYZ( Jzazbz) { // JzAzBz 배열을 D65 XYZ로 변환 // [0,0,0]은 블랙이고, // 미디어 화이트는 [0.2220, -0.00016, -0.0001] const b= 1.15 ; const g= 0.66 ; const M= [ [ 1.9242264357876067 , - 1.0047923125953657 , 0.037651404030618 ], [ 0.35031676209499907 , 0.7264811939316552 , - 0.06538442294808501 ], [ - 0.09098281098284752 , - 0.3127282905230739 , 1.5227665613052603 ], ]; let LMS= Jzazbz_to_LMS( Jzazbz); // 보정된 절대 XYZ let [ Xm, Ym, Za] = multiplyMatrices( LMS, M); // X와 Y 보정을 되돌려 미디어 화이트 기준의 D65 XYZ 획득 let Xa= ( Xm+ ( b- 1 ) * Za) / b; let Ya= ( Ym+ ( g- 1 ) * Xa) / g; return [ Xa, Ya, Za]; } function Jzazbz_to_LMS( Jzazbz) { const d= - 0.56 ; const d0= 1.6295499532821566e-11 ; const c1= 3424 / 2 ** 12 ; const c2= 2413 / 2 ** 7 ; const c3= 2392 / 2 ** 7 ; const pinv= 2 ** 5 / ( 1.7 * 2523 ); const M= [ [ 1 , 0.13860504327153927 , 0.05804731615611883 ], [ 1 , - 0.1386050432715393 , - 0.058047316156118904 ], [ 1 , - 0.09601924202631895 , - 0.81189189605603900 ], ]; let [ Jz, az, bz] = Jzazbz; let Iz= ( Jz+ d0) / ( 1 + d- d* ( Jz+ d0)); // LMS 원추체 도메인으로 변환 let PQLMS= multiplyMatrices([ Iz, az, bz], M); // PQ 부호화를 풀어 선형광 LMS로 변환 let LMS= ( PQLMS. map( function ( val) { let num= c1- spow( val, pinv); let denom= c3* spow( val, pinv) - c2; let x= 10000 * spow( num/ denom, ninv); return x; // 미디어 화이트 대비 휘도, 대략 [0, 70] }) ); return LMS; }
11.5. ICtCp 샘플 코드
변환을 rec2100-linear로 먼저 수행하도록 요구하는 [Rec_BT.2100]의 정의와 달리, 이 샘플 코드는 다른 색상 변환 코드와의 호환성을 위해 절대 CIE XYZ에서 바로 진행합니다.
4% 크로스토크 행렬과 hue 회전도 XYZ→LMS 단계에 포함되어 있으며, 세 단계로 따로 적용하지 않습니다.
최종 결과는 동일하며, 단계만 줄였습니다.
function XYZ_to_ICtCp( XYZ) { // D65 XYZ 배열을 ICtCp로 변환 // 아래 행렬은 4% 크로스토크 성분을 포함하며, // Dolby "What is ICtCp" 논문의 절차를 따릅니다 const M= [ [ 0.3592832590121217 , 0.6976051147779502 , - 0.0358915932320290 ], [ - 0.1920808463704993 , 1.1004767970374321 , 0.0753748658519118 ], [ 0.0070797844607479 , 0.0748396662186362 , 0.8433265453898765 ], ]; let LMS= multiplyMatrices( M, XYZ. map( v=> v* Yw)); return LMStoICtCp( LMS); } function LMStoICtCp( LMS) { const c1= 3424 / 4096 ; const c2= 2413 / 128 ; const c3= 2392 / 128 ; const m1= 2610 / 16384 ; const m2= 2523 / 32 ; // 이 행렬은 Ebner LMS 계수, 회전, // 그리고 [-0.5, 0.5] 범위로의 스케일을 포함합니다 // 유리수 항은 Fröhlich p.97 및 ITU-R BT.2124-0 pp.2–3 참조 const M= [ [ 2048 / 4096 , 2048 / 4096 , 0 ], [ 6610 / 4096 , - 13613 / 4096 , 7003 / 4096 ], [ 17933 / 4096 , - 17390 / 4096 , - 543 / 4096 ], ]; // PQ EOTF 적용 // [0, 10,000] → [0, 1]로 스케일됨 // 분모에 "1 +"가 있어 0으로 나눌 일은 없음 let PQLMS= LMS. map( function ( val) { let num= c1+ ( c2* (( val/ 10000 ) ** m1)); let denom= 1 + ( c3* (( val/ 10000 ) ** m1)); return ( num/ denom) ** m2; }); // Y'C'bC'r 호환을 위한 회전 포함 LMS→IPT return multiplyMatrices( M, PQLMS); } function ICtCp_to_XYZ( ICtCp) { // ICtCp를 절대 D65 XYZ 배열로 변환 const M= [ [ 2.0701522183894223 , - 1.3263473389671563 , 0.2066510476294053 ], [ 0.3647385209748072 , 0.6805660249472273 , - 0.0453045459220347 ], [ - 0.0497472075358123 , - 0.0492609666966131 , 1.1880659249923042 ], ]; let LMS= ICtCptoLMS( ICtCp); return multiplyMatrices( M, LMS); } function ICtCptoLMS( ICtCp) { const c1= 3424 / 4096 ; const c2= 2413 / 128 ; const c3= 2392 / 128 ; const im1= 16384 / 2610 ; const im2= 32 / 2523 ; const M= [ [ 0.9999999999999998 , 0.0086090370379328 , 0.1110296250030260 ], [ 0.9999999999999998 , - 0.0086090370379328 , - 0.1110296250030259 ], [ 0.9999999999999998 , 0.5600313357106791 , - 0.3206271749873188 ], ]; let PQLMS= multiplyMatrices( M, ICtCp); // PQ 인코딩 해제 (BT.2124-0 부록 2 Conversion 3) let LMS= PQLMS. map( function ( val) { let num= Math. max(( val** im2) - c1, 0 ); let denom= ( c2- ( c3* ( val** im2))); return 10000 * (( num/ denom) ** im1); }); return LMS; }
11.6. hdr-color() 샘플 코드
function hdrColor( col1, H1, col2, H2, H) { // col1, col2: 절대 XYZ에서 두 색을 나타내는 배열 // H1, H2: 각 색의 헤드룸(스톱, 로그 스케일, 0 = SDR) // H: 사용 가능한 헤드룸 // 헤드룸 값이 서로 다른지 확인 if ( H1== H2) return 0 ; let w1= clamp(( H- H2) / ( H1- H2), 0 , 1 ); let w2= clamp(( H- H1) / ( H2- H1), 0 , 1 ); let eps= 0.001 ; let cxyz= Array( 3 ); for ( let i= 0 ; i< 3 ; i++ ) { cxyz[ i] = Math. pow( c1xyz[ i] + eps, w1) * Math. pow( c2xyz[ i] + eps, w2) - eps; } return cxyz; } const clamp= ( n, min, max) => Math. min( Math. max( n, min), max)
12. ΔEITP 색상 차이 샘플 코드
이 절은 규범적인 내용이 아닙니다.
Tests
이 절은 규범적인 내용이 아니며, 테스트가 필요하지 않습니다.
ΔEITP [Rec_BT.2124] 색상 차이 지표는 HDR 또는 SDR/HDR 혼합 컨텍스트에서 디스플레이 기준 색상 두 개 사이의 지각적 색상 차이를 측정하는 데 사용할 수 있습니다. 예를 들어 디스플레이 캘리브레이션이나 가멋/톤 매핑에서 사용됩니다.
이는 ICtCp 색 공간에서의 유클리드 거리이며, ΔEITP 1.0이 막 지각 가능한 차이 1단계를 나타내도록 스케일링됩니다.
// deltaE ITP 계산 // 스케일된 제곱합의 제곱근 // ITU-R BT.2124-0 부록 1 /** * @param {number[]} reference - ICtCp 배열: I는 0..1, Ct와 Cp는 -1..1 * @param {number[]} sample - ICtCp 배열: I는 0..1, Ct와 Cp는 -1..1 * @return {number} 표본 색상이 기준과 얼마나 다른지 */ function deltaEITP( reference, sample) { let [ I1, Ct1, Cp1] = reference; let [ I2, Ct2, Cp2] = sample; let ΔI= I1- I2; let ΔT= 0.5 * ( Ct1- Ct2); let ΔP= Cp1- Cp2; return 720 * Math. sqrt( ΔI** 2 + ΔT** 2 + ΔP** 2 ); }
프라이버시 고려 사항
웹 플랫폼이 HDR 헤드룸의 수치 값을 직접 노출하지 않는 이유는, 그렇게 할 경우 현재의 시청 환경이 노출되어 이는 프라이버시 침해가 되기 때문입니다.
보안 고려 사항
이 문서에 대해서는 보안 관련 우려가 제기되지 않았습니다
접근성 고려 사항
일부 사용자는 매우 밝은 색상에 민감할 수 있으므로, 사용자 에이전트는 사용자가 선택할 수 있도록 최대 휘도를 제한하는 메커니즘을 제공해야 합니다. [Rec_BT.2390] 5.4.1절 제한된 밝기 범위를 가진 디스플레이로의 매핑의 toe와 knee 절차가 적합한 방법으로 제안됩니다.
dynamic-range-limit 속성은 사용자 스타일시트에서 standard 또는 constrained로 설정할 수도 있습니다.
변경 사항
2024년 12월 17일 최초 공개 워킹 드래프트이후 변경 사항
- eps에 대한 근거로서 SMPTE-ST-2094-50 언급을 제거 (#12873, #11788)
- hdr-color가 적응형 게인 곡선과 유사함을 명시
- color 구문에 alpha() RCS 추가 #10689
- 보간을 위한 색 공간에 display-p3-linear 추가 (#12596)
- deltaE ITP 예제 몇 가지 추가 (#11250)
- display-p3-linear 색 공간 추가 (#12596)
- hdr-color()에서 사용하는 clamp 함수 추가
- hdr-color() 샘플 코드 추가
- eps 계수의 용도 설명 (#11788)
- color-hdr() 두 번째 예제 추가
- "Absolute D65 CIE XYZ" 용어 정의
- color-hdr()의 의사코드를 명확히 하여 각 성분이 별도로 계산됨을 표시 (#11694)
- dynamic-range-limit-mix()에서 WG 결의에 따라 '하나 이상'으로 변경 (#11694)
- dynamic-range-limit-mix()의 계산값이 모든 매개변수가 생략되었을 때 초기값이 됨을 명확히 함 (#11678)
- color() 재정의를 제거하고 CSS Color 5의 정의로 연결 (#11954)
- WG 결의에 따라 "constrained-high"를 "constrained"로 되돌림 (#11698)
- JzCzhz의 크로마에 대한 epsilon을 정의하여 누락된 hue 처리 (#11706)
- "required conversion" 용어를 적절히 export하고 일관되게 사용
- JzCzhz에서 잘못된 음의 크로마 참조 범위를 제거
- 상대 ictcp, jzazbz, jzczhz에 대한 RCS 구성 요소 키워드 추가 (#11713)
- color() 링크가 SDR 전용인 CSS Color 5로 되돌아가도록 가리키는 것을 방지
- ICtCp 소개의 정보성 절을 추가하고, 정의를 color()에서 분리하여 이동 (#11713)
- CSS Color 5에 이미 존재하는 중복 production 제거 (#11954)
- 참조 범위가 BT.2100 가멋을 포괄하도록 조정 (#11710)
- CSS WG 결의에 따라 "합이 0이면 무효"라는 문구 제거 (#11678)
- 선형(배수) 헤드룸이 아닌 로그(스톱) 정의의 헤드룸을 일관되게 사용 (#11787)
- "media white"가 아닌 선호 용어 "HDR reference white"를 일관되게 사용
- 색 보간 예제 추가 (#11616)
- 보간 알고리즘 추가 (#11616)
- 헤드룸으로 매개변수화된 색 보간 섹션 추가 (#11616)
- WG 결의에 따라 color-hdr 함수 추가. ISO 21496-1 정보성 참고 추가 (#11616)
- Jzazbz 샘플 코드 추가 (#9934)
- 샘플 코드에 누락된 부호 지수 함수 추가
- rec2100 색 공간 샘플 코드 추가 (#9934)
- ICtCp 샘플 코드 추가 (#9934)
- Perrin ICtCp 논문에 대한 정보성 참고 추가
- 새 섹션 추가, 색상 변환 샘플 코드 (#9934)
- Dolby "What is ICtCp" 백서에 대한 정보성 참고 추가 (#9934)
- dynamic-range-limit-mix()의 문법과 규격 문구를 명확히 함 (#11672)
- BT.2124의 ΔEITP 색상 차이 지표 추가 (#11250)
- dynamic-range-limit에 대해 high를 no-limit로 변경 (#11698)
- 서술 수정: dynamic-range-limit-mix는 2개 이상의 값을 받음 (#11694)
- 절대/상대 HDR 개념을 제거하고, 대신 scene-referred와 display-referred를 강조. media white를 기준점으로 고정하고, color re-rendering을 허용 (#10460)
- "media white"를 더 명확히 정의
- 설명 자료를 모아 서론 섹션으로 정리