CSS 색상 HDR 모듈 레벨 1

W3C 최초 공개 작업 초안,

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2025/WD-css-color-hdr-1-20251202/
최신 공개 버전:
https://www.w3.org/TR/css-color-hdr-1/
편집자 초안:
https://drafts.csswg.org/css-color-hdr-1/
변경 이력:
https://www.w3.org/standards/history/css-color-hdr-1/
피드백:
CSSWG 이슈 저장소
명세 내 인라인
편집자:
Chris Lilley (W3C)
이 명세에 대한 수정 제안:
GitHub 편집기
테스트 스위트:
https://wpt.fyi/results/css/css-color-hdr/

초록

이 모듈은 High Dynamic Range(HDR)을 가능하게 하기 위해 CSS Color 4와 5에 대한 추가 사항을 정의합니다.

CSS는 구조화된 문서 (예: HTML 및 XML)의 렌더링을 화면, 종이 등에서 기술하는 언어입니다.

이 문서의 현황

이 섹션은 이 문서가 발행된 시점의 상태를 설명합니다. 현재 W3C의 모든 발행물 목록과 이 기술 보고서의 최신 개정본은 W3C 표준 및 초안 색인에서 확인할 수 있습니다.

이 문서는 CSS 작업 그룹에 의해 작업 초안으로, 권고안 절차를 사용하여 발행되었습니다. 작업 초안으로 발행되었다고 해서 W3C 및 그 구성원의 승인을 의미하지는 않습니다.

본 문서는 초안 문서이며, 언제든지 업데이트, 교체, 또는 다른 문서로 대체될 수 있습니다. 진행 중인 작업 외의 목적으로 이 문서를 인용하는 것은 적절하지 않습니다.

피드백은 GitHub에 이슈를 등록하는 방식(권장)에 의해 보내주시기 바랍니다. 제목에 명세 코드 “css-color-hdr”를 포함해주세요. 예시: “[css-color-hdr] …의견 요약…”. 모든 이슈와 댓글은 아카이브에 기록됩니다. 또는, (아카이브) 공개 메일링 리스트 www-style@w3.org에 피드백을 보낼 수 있습니다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받습니다.

이 문서는 W3C 특허 정책 하에서 운영되는 그룹에 의해 생성되었습니다. W3C는 그룹의 결과물과 관련하여 공개 특허 공개 목록을 유지관리하며; 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특허에 관한 실제 정보를 알고 있으며, 해당 특허가 필수 청구항(Essential Claim(s))을 포함한다고 생각하는 개인은 W3C 특허 정책 6항에 따라 정보를 공개해야 합니다.

1. 소개

이 절은 규범적인 내용이 아닙니다.

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

네 가지 색 공간의 전기-광 전달 함수(EOTF): 확장 sRGB와 선형광 sRGB(CSS Color 4에서 정의됨), 그리고 본 명세에서 정의된 PQ(Perceptual Quantizer), HLG(Hybrid Log-Gamma)를 보여줍니다. 출처: [Rec_BT.2100].

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 기준 백색은 가장 밝은 색이며, 최대 밝기의 빨강, 초록, 파랑으로 생성됩니다.

예를 들어, sRGB에서 표준 시청 조건 하에, 흰색의 휘도는 80 cd/m², 검정의 휘도는 0.2 cd/m²로 정의됩니다. 따라서 다이내믹 레인지는 8.6스톱입니다.

화면의 전체 밝기를 사용자의 취향이나 표준과 다른 시청 조건에 맞추어 조정하는 경우가 흔합니다.

SDR의 경우, 화면을 더 밝게 하더라도 다이내믹 레인지는 변하지 않습니다. 가장 어두운 색도 같이 밝아지기 때문입니다.

예를 들어, sRGB 화면에서 흰색의 휘도를 160 cd/m²로 맞춘다면, 가장 어두운 검정은 0.4 cd/m²가 됩니다. 다이내믹 레인지는 여전히 8.6스톱입니다.

하이 다이내믹 레인지(HDR)에서는, HDR 기준 백색보다 더 밝은 색상을 표시할 수 있습니다. 예를 들어, HDR 디스플레이에서 HDR 기준 백색이 203 cd/m²로 설정된 경우, 작은 하이라이트를 1000 cd/m²까지 표시할 수 있습니다. 일반적으로 가장 밝은 색상은 디스플레이의 일부 영역에서만, 제한된 시간 동안 표시할 수 있습니다. 이는 에너지 사용과 발열 때문입니다.

예를 들어, HDR 기준 마스터링 디스플레이에서, 소면적 최고 백색(peak white)은 1000 cd/m², 가장 어두운 검정은 0.05 cd/m²의 휘도를 가질 수 있습니다. 따라서 다이내믹 레인지는 14.3스톱입니다.

HDR의 경우, 화면을 더 밝게 하면 다이내믹 레인지가 증가하며, HDR 기준 백색의 휘도는 변하지 않습니다.

예를 들어, rec2100-pq 색 공간을 사용하는 경우 ( [Rec_BT.2100] 정의), 가장 밝은 백색의 휘도는 10,000 cd/m², 가장 어두운 검정의 휘도는 0.001 cd/m²입니다. 따라서 인코딩된 다이내믹 레인지는 23.3스톱입니다.

로그 스케일의 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 디스플레이 (가장 낮은 등급의 VESA DisplayHDR 인증인 DisplayHDR 400 맞는 제품, [DisplayHDR]) HDR 기준 백색을 최대 200 cd/m2로, 피크 화이트는 400 cd/m2로 표시할 수도 있습니다(가장 밝은 HDR 기준 백색에서 HDR 헤드룸이 단 1스톱).
예를 들어, 고급 HDR 디스플레이 (현재 VESA DisplayHDR 인증 최고 등급인 DisplayHDR 1400 이상), HDR 기준 백색을 최대 400 cd/m2로, 피크 화이트는 1600 cd/m2까지 표시할 수 있습니다.

암전 시청 환경에서 HDR 기준 백색을 100 cd/m2로 맞추면, HDR 헤드룸이 4스톱(16배)이 됩니다.

웹 플랫폼은 현재 디스플레이의 헤드룸 수준을 직접적으로 노출하지 않습니다. 시청 조건, 실시간 미계량 헤드룸 정보는 추적 벡터가 되기 때문입니다 (예: 사용자가 실외로 이동했거나 쾌청한 날씨임을 탐지하는 용도 등).

항상 사용 가능한 최대 HDR 헤드룸을 사용하는 것이 바람직하지 않을 수 있습니다. CSS는 대략적으로 얼마나 많은 헤드룸을 사용할지 제어하는 방법을 제공합니다. 이 값은 엘리먼트별, 시간별로 달라질 수 있습니다.

예를 들어, 사진 그리드를 표시하는 웹 페이지를 생각해봅시다. 여기에는 HDR 사진, 그리고 태양을 정면으로 촬영한 매우 높은 다이내믹 레인지 이미지도 포함될 수 있습니다. 전체 사진을 최대 다이내믹 레인지로 보면 피로감이 있을 수 있습니다. 동시에 모든 이미지를 SDR로 압축하면 각 사진의 개성이 제대로 표현되지 않을 수 있습니다. 설계 목표는 그룹 전체의 사진을 의미있게 감상할 수 있을 만큼의 "충분한" HDR 효과를 제공하는 것입니다.

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 콘텐츠를 함께 편안하게 감상할 수 있도록 합니다.
body { dynamic-range-limit: standard; }
div.photogrid img { dynamic-range-limit: constrained }

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()인 경우, 계산값은 아래 알고리즘에 의해 결정됩니다.

  1. v1, ..., vN을 혼합할 파라미터들의 계산값으로 둡니다.

  2. p1, ..., pN을 혼합 비율(백분율)로 두고, 합이 100%가 되도록 정규화합니다.

  3. 기여 백분율은 다음과 같이 정의합니다:

    • p1_standard,...,pN_standardv1,...,vNstandard의 비율로 둡니다.

    • p1_constrained_high,...,pN_constrained_highv1,...,vNconstrained의 비율로 둡니다.

    • p1_no_limit,...,pN_no_limitv1,...,vNno-limit의 비율로 둡니다.

  4. 가중합은 아래와 같이 계산합니다:

    • 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

  5. p_standard, p_constrained_high, p_no_limit 중 하나라도 100%라면, 계산값은 각각 standard, constrained, no-limit입니다.

  6. 그렇지 않으면 계산값은 dynamic-range-limit-mix()로, 파라미터는 standard, constrained, no-limit 순서 및 비율 p_standard, p_constrained_high, p_no_limit로 하며, 비율이 0%인 파라미터는 생략합니다. 모든 파라미터가 생략되면, 계산값은 초깃값(initial value)입니다.

테스트(Tests)
아래의 계산값:
dynamic-range-limit-mix(
    high 10%,
    dynamic-range-limit-mix(standard 25%, constrained 75%) 20%,
    dynamic-range-limit-mix(constrained 10%, no-limit 30%) 20%)

는 아래와 같습니다.

dynamic-range-limit-mix(standard 10%, constrained 40%, no-limit 50%)

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 헤드룸 기준 색상 보간에서 설명합니다.

이것은 래스터 이미지의 gain map 또는 [ISO_21496-1]과, 또는 [SMPTE-ST-2094-50]의 adaptive gain curves와 유사한 메커니즘입니다.

개인정보 보호상의 이유로, 실제로 계산된 색상이나 HDR 헤드룸 값은 드러나지 않습니다. 이것이 지문 추적 벡터가 될 수 있기 때문입니다.

구문은 다음과 같습니다:

hdr-color() = color-hdr([ <color> && <number [0,∞]>? ]#{2})
이 색상을 고려해봅시다:
color-hdr(
  color(rec2100-linear 0.9 1.0 0.8) 0,
  color(rec2100-linear 1.8 2.0 1.5) 2);

HDR 헤드룸 <= 0인, 즉 SDR 디스플레이에서는 이 색상은

color(rec2100-linear 0.9 1.0 0.8)

HDR 헤드룸가 2 이상인 디스플레이에서는 이 색상은

color(rec2100-linear 1.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 기준 백색의 휘도)로 나타냅니다.

예를 들어, CSS 색상 white
color(xyz-d65 0.9505 1 1.089)

절대 D65 XYX로 변환하면 [192.9426, 203, 221.0787]이 됩니다.

5.1. 헤드룸 기준 색상 보간

헤드룸 H1에서의 색상 c1과 헤드룸 H2에서의 색상 c2 사이를 보간하여, 대상 헤드룸이 H일 때 결과 색상 cxyz를 얻으려면:

  1. c1xyzc1절대 D65 CIE XYZ로 변환한 값으로 둡니다.

  2. c2xyzc2절대 D65 CIE XYZ로 변환한 값으로 둡니다.

  3. w1 = clamp((H - H2) / (H1 - H2), 0, 1)

  4. w2 = clamp((H - H1) / (H2 - H1), 0, 1) w2 = 1 - w1임에 유의하십시오.

  5. eps = 0.001로 둡니다.

  6. cxyz = Array(3)로 둡니다.

  7. i를 0부터 2까지 반복하며: cxyz[i] = pow(c1xyz[i] + eps, w1 ) * pow(c2xyz[i] + eps, w2 ) - eps

참고: eps는 0으로 나누는 경우를 방지하며, SDR 색상과 같이 검정에 가까운 색을 보간할 때 특히 중요합니다.

예를 들어, c1 = color(rec2100-linear 0.9 1.0 0.8), c2 = color(rec2100-linear 1.8 2.0 1.5), H1 = 0, H2 = 2, H = 1일 때:
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 ]
예를 들어, c1 = color(display-p3 1 1 0.33), c2 = jzczhz(70% 0.14 100), H1 = 0.5, H2 = 4, H = 2일 때:
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 혼합 컬러 검출에 적합합니다.

예를 들어 BT.2020과 BT.2100은 동일한 원색과 화이트포인트를 사용합니다. BT.2020은 SDR, BT.2100은 HDR이며 HDR 기준 백색을 약 0.58 코드 값에 둡니다.

아주 넓은 가멋의 원색 빨강 예시:

color(rec2100-pq 0.58 0 0) /* ictcp(44.6% -0.129 0.399) */
color(rec2020 1 0 0)       /* ictcp(44.7% -0.130 0.399)  */

이 두 색상은 ICTCP 상 매우 가깝고 deltaE ITP는 0.487이므로 시각적 차이가 없습니다.

이들은 sRGB "red"와는 매우 다르게 나타납니다:

color(rec2100-pq 0.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에서 sRGB 색상 "lime"을 나타냅니다.
 ictcp(0.5393 -0.2643 -0.0625)
이 색상은 편안한 "diffuse white"를 나타냅니다. 이 색상은 장시간 표시하거나, 모든 화면 크기에 자막으로 사용할 수 있습니다. sRGB white와 동일한 색상입니다. Diffuse white는 203 cd/m² [Rec_BT.2100]입니다.
 ictcp(0.58069 0 0)

상대 색상 구문에서 ictcp() 함수의 허용 성분 키워드는 다음과 같습니다:

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 간 변환을 위한 샘플 코드가 제공됩니다.

이 색상은 편안한 "diffuse white"를 나타냅니다. 이 색상은 장시간 표시하거나, 모든 화면 크기에 자막으로 사용할 수 있습니다. sRGB white와 동일한 색상입니다. Diffuse white는 203 cd/m² [Rec_BT.2100]입니다.
 jzazbz(0.22207 -0.00016 -0.00012)

상대 색상 구문에서 jzazbz() 함수의 허용 컴포넌트 키워드는 아래와 같습니다:

6.5. JzCzhz

LCH가 Lab의 극좌표 표현인 것처럼, JzCzhzJzazbz의 극좌표형입니다.

JzJzazbz의 값과 동일하며, 명도를 나타냅니다. 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에서 sRGB 색상 "lime"을 나타냅니다.
 jzazbz(0.17542 -0.1179 0.1092)

그리고 아래는 같은 색상의 극좌표 표현입니다.

 jzczhz(0.17542 0.1614 132.50)

상대 색상 구문에서 jzczhz() 함수의 허용 컴포넌트 키워드는 아래와 같습니다:

6.5.1. Jzazbz 색상을 JzCzhz 색상으로 변환

JzCzhz로의 변환은 단순합니다:

  1. hz = atan2(bz, az) // 단, 각도로 변환해야 함!
  2. Cz = sqrt(az^2 + bz^2)
  3. Jz는 동일

실제 코드에서는 Cz가 ε보다 작으면 none 값을 반환해야 합니다.

6.5.2. JzCzhz 색상을 Jzazbz 색상으로 변환

Jzazbz로의 변환도 단순합니다:

  1. az = Cz cos(H) // 먼저 라디안으로 변환!
  2. bz = Cz sin(H) // 먼저 라디안으로 변환!
  3. 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에 해당합니다.

이 색상은 10,000 cd/m² 휘도의 눈부신 흰색을 나타냅니다. 이렇게 밝은 색상은 화면 일부에서만, 짧은 시간 표시 가능합니다. 일반적으로 콘텐츠는 4,000 cd/m² 등 더 낮은 피크 화이트 기준으로 마스터링됩니다.
 color(rec2100-pq 1.0 1.0 1.0);
이 색상은 편안한 "diffuse white"(산란 흰색)를 나타냅니다. 이 색상은 오랜 시간 표시하거나, 화면 크기에 관계없이 자막 등에 사용할 수 있습니다. sRGB white와 동일한 색상입니다. Diffuse white는 203 cd/m² [Rec_BT.2100]입니다.
 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과 일치합니다.

추가 예시 필요

이 색상은 편안한 "diffuse white"(산란 흰색)를 나타냅니다. 이 색상은 오랜 시간 표시하거나, 화면 크기에 관계없이 자막 등에 사용할 수 있습니다. 콘텐츠는 보통 피크 화이트가 1,000~4,000 cd/m²로 마스터링되기 때문에, diffuse white는 203~581 cd/m²입니다.
 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-linear 1 1 1)
예를 들어, 아래 색상은
color(rec2100-linear 9.852 9.852 9.852)

휘도 9.852 × 203 = 1,999 cd/m²의 화이트 하이라이트를 나타냅니다.

이 색상은 편안한 "diffuse white"(산란 흰색)를 의미합니다. 이 색상은 오랜 시간 표시하거나, 화면 크기에 관계없이 자막 등에 사용할 수 있습니다. sRGB white와 동일한 색상입니다. Diffuse white는 203 cd/m² [Rec_BT.2100]입니다.
 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일 최초 공개 워킹 드래프트이후 변경 사항

적합성

문서 규약

적합성 요구 사항은 설명적 진술과 RFC 2119 용어의 조합으로 표현됩니다. 본 문서의 규범적 부분에서 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", "OPTIONAL" 등의 키워드는 RFC 2119에서 설명된 대로 해석되어야 하며, 가독성을 위해 모두 대문자로 표기되지는 않습니다.

이 명세의 모든 텍스트는 별도로 비규범, 예시, 노트로 명시된 부분을 제외하고는 규범적입니다. [RFC2119]

이 명세서의 예시는 "for example"이라는 문구로 시작하거나 class="example"와 같이 규범적 본문과 구분됩니다.

이것은 정보 제공 목적의 예시입니다.

정보를 제공하는 노트는 "Note"로 시작하며 class="note"로 구분됩니다.

Note, 이것은 정보 제공 목적의 노트입니다.

권고(advisement)는 특별한 주의를 환기하기 위해 규범적 부분을 스타일링한 섹션이며, <strong class="advisement">로 구분되어 있습니다. 예: UA는 접근 가능한 대체 수단을 제공해야 합니다.

Tests

이 명세의 내용과 관련된 테스트는 이와 같은 “Tests” 블록에 문서화될 수 있습니다. 이러한 블록은 모두 비규범적입니다.


적합성 클래스

이 명세에 대한 적합성은 세 가지 적합성 클래스로 정의됩니다:

style sheet
CSS 스타일 시트
renderer
UA는 스타일 시트의 의미를 해석하고 해당 스타일 시트를 사용하는 문서를 렌더링합니다.
authoring tool
UA는 스타일 시트를 작성합니다.

이 모듈에서 정의된 구문을 사용하는 모든 문이 일반 CSS 구문 및 각 기능별 구문에 따라 유효하다면, 스타일 시트는 본 명세에 적합한 것입니다.

렌더러는, 적합한 명세서에 따라 스타일 시트를 해석하는 것 이외에도, 본 명세에서 정의된 모든 기능을 올바르게 구문 분석하고 문서를 렌더링해야 적합합니다. 단, 디바이스의 한계로 인해 UA가 문서를 올바르게 렌더링하지 못해도 비적합한 것은 아닙니다(예: UA가 흑백 모니터에서 색상을 렌더링할 필요는 없음).

작성 도구는 일반 CSS 구문 및 이 모듈의 각 기능별 구문에 따라 구문적으로 올바른 스타일 시트를 작성하며, 이 모듈에서 설명된 스타일 시트의 기타 모든 적합성 요건을 충족해야 적합합니다.

부분 구현

저자가 미래 호환 구문 분석 규칙을 활용해 대체값을 지정할 수 있도록, CSS 렌더러는 지원 수준이 없는 모든 at-rule, 속성, 속성값, 키워드 및 기타 구문 구조를 무효로 처리(필요에 따라 무시)해야 합니다. 특히, UA는 단일 멀티값 속성 선언에서 지원하지 않는 구성요소 값을 일부만 무시하거나 지원되는 값만 적용해서는 안 됩니다. 어떤 값이라도 무효로 간주되면 전체 선언을 무시해야 하며, 이는 CSS의 요구 사항입니다.

불안정 및 독점 기능의 구현

향후 안정적인 CSS 기능과의 충돌을 방지하기 위해, CSSWG는 베스트 프랙티스에 따라 불안정 기능 및 독점적 확장을 구현할 것을 권장합니다.

비실험적 구현

명세가 후보 권고(CR) 단계에 도달하면 비실험적 구현이 가능하며, 구현자는 명세에 따라 올바르게 구현되었음을 입증할 수 있는 CR 수준 기능의 접두어 없는 구현을 공개해야 합니다.

CSS의 상호 운용성을 수립하고 유지하기 위해 CSS 워킹 그룹은 비실험적 CSS 렌더러가 CSS 기능의 접두어 없는 구현을 공개하기 전에 구현 보고서(필요시 테스트케이스 포함)를 W3C에 제출해 줄 것을 요청합니다. W3C에 제출된 테스트케이스는 CSS 워킹 그룹의 검토 및 수정 대상입니다.

테스트케이스 및 구현 보고서 제출과 관련된 추가 정보는 CSS 워킹 그룹 웹사이트 https://www.w3.org/Style/CSS/Test/에서 확인할 수 있습니다. 문의는 public-css-testsuite@w3.org 메일링 리스트로 하십시오.

색인

이 명세서에서 정의된 용어

참조로 정의된 용어

참고문헌

규범적 참고문헌

[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 2022년 1월 13일. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou. CSS Color Module Level 4. 2025년 4월 24일. CRD. URL: https://www.w3.org/TR/css-color-4/
[CSS-COLOR-5]
Chris Lilley; et al. CSS Color Module Level 5. 2025년 3월 18일. WD. URL: https://www.w3.org/TR/css-color-5/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 2024년 3월 22일. CRD. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2024년 3월 12일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011년 6월 7일. REC. URL: https://www.w3.org/TR/CSS2/
[Rec.2020]
Recommendation ITU-R BT.2020-2: Parameter values for ultra-high definition television systems for production and international programme exchange. 2015년 10월. URL: http://www.itu.int/rec/R-REC-BT.2020/en
[Rec_BT.2100]
ITU-R BT.2100-3 Image parameter values for high dynamic range television for use in production and international programme exchange. 2025년 2월. URL: https://www.itu.int/rec/recommendation.asp?lang=en&parent=R-REC-BT.2100-3-202502-I
[Rec_BT.2390]
ITU-R BT.2390-8 High dynamic range television for production and international programme exchange. 2020년 2월. URL: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-8-2020-PDF-E.pdf
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[Rpt_BT.2408]
Report ITU-R BT.2408-0 Operational practices in HDR television production. 2017년 10월. URL: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2408-2017-PDF-E.pdf
[Safdar-PUCS]
Safdar, Muhammad; et al. Perceptually uniform color space for image signals including high dynamic range and wide gamut. 2017년 6월 26일. URL: https://opg.optica.org/oe/fulltext.cfm?uri=oe-25-13-15131&id=368272
[SMPTE-ST-2084]
ST 2084:2014 - SMPTE Standard - High Dynamic Range Electro-Optical Transfer Function of Mastering Reference Displays. 2014년 8월 29일. URL: https://pub.smpte.org/latest/st2084/st2084-2014.pdf

비규범적 참고문헌

[ARIB_STD-B67]
Essential Parameter Values for the Extended Image Dynamic Range Television (EIDRTV) System for Programme Production. 2015년 7월 3일. URL: https://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
[Development_ITP]
F.Ebner; M.D.Fairchild. Development and testing of a color space (IPT) with improved hue uniformity. In: Proceedings of The Sixth Color Imaging Conference, 8-13, 1998. 1998년 1월. URL: https://www.researchgate.net/publication/221677980_Development_and_Testing_of_a_Color_Space_IPT_with_Improved_Hue_Uniformity
[DisplayHDR]
Summary of DisplayHDR Specs under CTS 1.2. 2024년 5월 17일. URL: https://displayhdr.org/performance-criteria/
[ISO_21496-1]
Gain map metadata for image conversion: Part 1: Dynamic Range Conversion. URL: https://www.iso.org/standard/86775.html
[Perrin]
Perrin, A-F.; et al. ICtCp Versus Y'CbCr: Evaluation of ICtCp Color Space and an Adaptive Reshaper for HDR and WCG. 2018년 5월. URL: https://ieeexplore.ieee.org/document/8333011
[Rec_BT.2124]
ITU-R BT.2124-0 Objective metric for the assessment of the potential visibility of colour differences in television. URL: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2124-0-201901-I!!PDF-E.pdf
[Rec_BT.814]
Specifications of PLUGE test signals and alignment procedures for setting of brightness and contrast of displays. 2018년 7월. URL: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.814-4-201807-I!!PDF-E.pdf
[SMPTE-ST-2094-50]
Dynamic Metadata for Color Volume Transform - Application #5 (Broadcast). 2025년. URL: https://github.com/SMPTE/st2094-50
[What_is_ICtCp]
What is ICtCp, v7.1. URL: https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf

속성 색인

이름 초기값 적용 대상 상속 백분율 애니메이션 유형 정규 순서 계산값
dynamic-range-limit standard | no-limit | constrained | <dynamic-range-limit-mix()> no-limit 모든 요소 해당 없음 dynamic-range-limit-mix() 기준 문법에 따름 dynamic-range-limit의 계산값 참조

이슈 색인

로그 스케일로 SDR 및 HDR 다이내믹 레인지 다이어그램 추가
다른 예시 추가, sRGB 적, 녹, 청 및 P3 적, 녹, 청 인코딩 포함
다른 예시 추가
동일 페이지에서 정의된 black level lift Β 추가?