CSS 색상 HDR 모듈 레벨 1

W3C 최초 공개 작업 초안,

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2026/WD-css-color-hdr-1-20260624/
최신 공개 버전:
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 값 & 단위 [CSS-VALUES-3]에서 정의됩니다. 다른 CSS 모듈과의 결합은 이러한 값 유형의 정의를 확장할 수 있습니다.

각 정의에 나열된 속성별 값 외에도, 이 명세에서 정의하는 모든 속성은 CSS 전역 키워드도 속성값으로 허용합니다. 가독성을 위해 이를 명시적으로 반복하지 않았습니다.

'

2. HDR 용어

2.1. 다이내믹 레인지 정의

피크 휘도는 표시할 수 있는 가장 밝은 흰색의 휘도입니다. 이는 선형 광량이며, cd/m2 단위로 측정되고, 니트라고도 합니다.

가장 깊은 검정은 표시할 수 있는 가장 어두운 검정의 휘도입니다. 이는 시청 플레어 (화면에서 반사되는 주변광)의 영향을 받으므로, 실제 값은 시청 조건에 따라 달라집니다.

선형 동적 범위는 표시할 수 있는 가장 밝은 색과 가장 어두운 색 사이의 휘도 비율입니다.

동적 범위선형 동적 범위의 밑이 2인 로그입니다. 이는 우리의 눈이 밝기를 로그 스케일로 인지하기 때문입니다. 동적 범위는 사진학적 스톱으로 측정됩니다. 한 스톱은 휘도가 두 배가 되는 것입니다.

function DynamicRange (peak, deepest) {
  return Math.log2(peak) - Math.log2(deepest);
  } 

HDR 기준 백색은, 미디어 백색 또는 확산 백색이라고도 하며, [Rpt_BT.2408-9] 2.1절에서 정의되고, 표준값은 203 cd/m2입니다. 이는 일반적인 흰색 배경의 색, 또는 어두운 배경 위의 흰색 텍스트의 색입니다. 이는 전체 화면에서 편안하게 볼 수 있습니다.

표준 동적 범위(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 기준 마스터링 디스플레이에서는 작은 영역의 피크 백색이 1000 cd/m²의 휘도를 가질 수 있고, 가장 깊은 검정은 0.05 cd/m²의 휘도를 가질 수 있습니다. 따라서 동적 범위는 14.3스톱입니다.

HDR에서는 더 밝은 화면을 사용하면 동적 범위가 증가하는 반면, HDR 기준 백색의 휘도는 일정하게 유지됩니다.

예를 들어, [Rec_BT.2100]에서 정의된 rec2100-pq 색공간을 사용하면, 가장 밝은 피크 백색은 10,000 cd/m²의 휘도를 갖도록 정의되고 가장 깊은 검정은 0.001 cd/m²의 휘도를 갖습니다. 따라서 인코딩된 동적 범위는 23.3스톱입니다.

SDR 및 HDR 동적 범위를 로그 스케일로 보여주는 다이어그램 추가

§ 9 SDR 및 HDR 콘텐츠 합성과 색공간 변환의 경우, SDR 콘텐츠의 HDR 기준 백색은 203 cd/m² [Rpt_BT.2408-9]에 고정되어야 하며, 그래야 합성 입력의 HDR 기준 백색 수준이 결합된 신호의 HDR 기준 백색 수준에 도달하게 됩니다.

HDR(또는 SDR과 HDR이 혼합된) 콘텐츠를 표시할 때, 기준 마스터링 디스플레이보다 성능이 낮은 디스플레이와 표준 조건과 다른 시청 조건의 경우, 색 재렌더링 단계((OOTF)가 수행됩니다. 이로 인해 HDR 기준 백색이 203 cd/m²보다 낮거나 높은 값으로 표시될 수 있습니다.

2.2. 헤드룸 소개

HDR 디스플레이가 생성할 수 있는 피크 휘도 수준은 크게 달라집니다.

피크 휘도가 HDR 기준 백색보다 큰 정도를 선형 HDR 헤드룸이라고 하며, 그 값은 HDR 기준 백색의 수준, 사용자 선호도, 그리고 시청 조건에 따라 달라집니다.

예를 들어, 어떤 디스플레이가 HDR 기준 백색을 160 cd/m2로 표시하고 피크 휘도가 1000 cd/m2라면 이 디스플레이는 1000 / 160 = 6.25배의 선형 HDR 헤드룸을 갖습니다.

HDR 헤드룸선형 HDR 헤드룸의 밑이 2인 로그이며, 동적 범위와 마찬가지로 사진학적 스톱으로 표현됩니다.

function Headroom (peak, reference) {
  return Math.log2(peak) - Math.log2(reference);
  } 
예를 들어, 어떤 디스플레이가 HDR 기준 백색을 160 cd/m2로 표시하고 피크 휘도가 1000 cd/m2라면 이 디스플레이는 log2(1000) - log2(160) = 2.64스톱의 HDR 헤드룸을 갖습니다.

따라서 표준 동적 범위(SDR)는 정의상 0스톱의 HDR 헤드룸을 갖습니다. 가장 밝은 흰색이 HDR 기준 백색과 같기 때문입니다.

예를 들어, 저가형 HDR 디스플레이는 (DisplayHDR 400, 즉 Vesa Certified DisplayHDR 적합성의 최하위 등급 [DisplayHDR]의 요구 사항을 겨우 충족하는 디스플레이) HDR 기준 백색을 최대 200 cd/m2로 표시할 수 있는 반면, 피크 백색은 400 cd/m2에 불과할 수 있습니다. (가장 밝은 HDR 기준 백색에서 HDR 헤드룸은 1스톱뿐입니다).
예를 들어, 고급 HDR 디스플레이는 (Vesa Certified DisplayHDR 적합성의 현재 최고 등급인 DisplayHDR 1400의 요구 사항을 초과하는 디스플레이) HDR 기준 백색을 최대 400 cd/m2로 표시할 수 있는 반면, 그 피크 백색은 1600 cd/m2일 수 있습니다.

어두운 시청 조건에서, HDR 기준 백색을 100 cd/m2로 설정하면, 이는 4스톱의 HDR 헤드룸 (16배의 선형 HDR 헤드룸)을 제공합니다.

웹 플랫폼은 현재 디스플레이의 헤드룸 수준을 직접 노출하지 않습니다. 이는 시청 조건에 따라 달라지고, 실시간의 양자화되지 않은 헤드룸 정보는 추적 벡터가 될 수 있기 때문입니다. (예를 들어, 사용자가 밖으로 이동했고 날씨가 맑다는 것을 감지하는 경우).

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()> |
    <hdr-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 사이에 있는 디스플레이에서는 색상이 보간됩니다. 예를 들어 처럼, HDR 헤드룸이 1인 디스플레이에서는 다음과 같습니다.

X = 243.664, Y = 275.713, Z = 244.000

색상은 절대 D65 CIE XYZ에서 보간됩니다.

이는 xyz-d65에서 파생되며, 각 색상 성분에 203 [Rpt_BT.2408-9]을 곱하여 상대 단위(실제 밝기와 관계없이 흰색의 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 이상일 때 변형 없이 사용됩니다.

예를 들어, c1 = ictcp(50% -0.3 0), c2 = ictcp(85% -0.35 0.1), H1 = 0, H2 = 4일 때, 이는 CSS에서는 다음과 같이 표현됩니다:
color-hdr(
  var(--c1) 0,
  var(--c2) 4
)

H = 2.3인 경우

c1xyz = [63.6, 96.53, 8.558]
c2xyz = [2521, 2508, 112.2]
w1 = 0.425
w2 = 0.575
cxyz = [527.68, 628.20, 37.59]

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 [Safdar-PUCS]와 비교해 더 뛰어난 색상 균일성을 가집니다.

CIE Lab은 HDR 기준 백색에 상대적인 [0%, 100%] 범위의 명도 스케일을 사용합니다. 마찬가지로 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]은 선형 광 BT.2100 RGB [Rec_BT.2100]에서의 변환으로 ICTCP를 정의하지만, 이 변환은 LMS를 거쳐 진행되므로 [What_is_ICtCp]에 표시된 것처럼 XYZ에서 LMS로의 변환을 적용하여 다른 모든 색공간도 나타낼 수 있습니다. 샘플 코드는 이 접근 방식을 사용합니다.

이 색상은 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 § 16. <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);
이 색상은 편안한 "확산 백색"을 나타냅니다. 이 색상은 장시간 표시하거나, 자막에 사용하거나, 화면의 어떤 크기 영역에도 사용할 수 있습니다. 이는 sRGB 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 red, green, blue 및 P3 red, green, blue의 인코딩을 포함하여 다른 예제 추가.

선형 광 RGB 신호는 다음과 같이 PQ 인코딩으로 변환됩니다. PQ에서 인코딩 가능한 최대값(피크, 작은 영역의 백색)은 10,000 cd/m²입니다. HDR 기준 백색은 203 cd/m²입니다 [Rpt_BT.2408-9].

var Er;			// 빨강, 초록 또는 파랑 성분, SDR의 경우 [0, 1], HDR의 경우 [0, 대략 70]
var Yw = 203;	// 확산 백색의 휘도, 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;			// 확산 백색의 휘도, cd/m²
var Ea = x * 10000; 	// 휘도, [0, 10,000].
var Er = x * 10000 / Yw; 	// 확산 백색에 상대적인 휘도, [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과 일치합니다.

추가 예시 필요

이 색상은 편안한 "확산 백색"을 나타냅니다. 이 색상은 장시간 표시하거나, 자막에 사용하거나, 화면의 어떤 크기 영역에도 사용할 수 있습니다. 콘텐츠는 일반적으로 피크 백색이 1,000에서 4,000 cd/m²인 상태로 마스터링되므로, 확산 백색은 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;
}

같은 페이지에 정의된 검정 수준 리프트 Β를 추가할까요?

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-9]

PQ 전달 함수를 사용하는 HDR은 SDR HDR 기준 백색을 58% PQ 값을 표시하는 데 사용되는 것과 같은 휘도인 203 cd/m²에 매핑해야 합니다. [SMPTE-ST-2084].

그러나 구현은 기준 시청 조건이 아닌 조건을 고려하기 위해 색 재렌더링 단계를 포함하도록 선택할 수도 있습니다.

10. <color> 값 직렬화

10.1. color() 함수 값 직렬화

이 절은 CSS Color 4 § 16.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 §  19. 색상 변환 샘플 코드의 모든 변환 코드가 사용 가능하다고 가정합니다.

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로 설정할 수도 있습니다.

변경 사항

다음 이후 변경 사항: 2026년 3월 3일 작업 초안

다음 이후 변경 사항: 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 캐스케이딩 및 상속 레벨 5. 2022년 1월 13일. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-4]
Tab Atkins Jr.; Chris Lilley; Lea Verou. CSS 색상 모듈 레벨 4. 2026년 6월 18일. CRD. URL: https://www.w3.org/TR/css-color-4/
[CSS-COLOR-5]
Chris Lilley; Una Kravets; Lea Verou. CSS 색상 모듈 레벨 5. 2026년 6월 18일. WD. URL: https://www.w3.org/TR/css-color-5/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 값과 단위 모듈 레벨 3. 2024년 3월 22일. CRD. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 값과 단위 모듈 레벨 4. 2024년 3월 12일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. 캐스케이딩 스타일 시트 레벨 2 개정판 1 (CSS 2.1) 명세. 2011년 6월 7일. REC. URL: https://www.w3.org/TR/CSS2/
[Rec.2020]
Recommendation ITU-R BT.2020-2: 제작 및 국제 프로그램 교환을 위한 초고화질 텔레비전 시스템의 매개변수 값. 2015년 10월. URL: http://www.itu.int/rec/R-REC-BT.2020/en
[Rec_BT.2100]
ITU-R BT.2100-3 제작 및 국제 프로그램 교환에 사용되는 고동적 범위 텔레비전의 이미지 매개변수 값. 2025년 2월. URL: https://www.itu.int/rec/recommendation.asp?lang=en&parent=R-REC-BT.2100-3-202502-I
[Rec_BT.2390]
제작 및 국제 프로그램 교환을 위한 고동적 범위 텔레비전. 2025년 3월. URL: https://www.itu.int/pub/R-REP-BT.2390-12-2025
[RFC2119]
S. Bradner. RFC에서 요구 수준을 나타내기 위해 사용하는 핵심어. 1997년 3월. 현재 모범 사례. URL: https://datatracker.ietf.org/doc/html/rfc2119
[Rpt_BT.2408-9]
고동적 범위 텔레비전 제작에서의 운용 관행을 위한 지침. 2026년 3월. URL: https://www.itu.int/pub/R-REP-BT.2408-9-2026
[Safdar-PUCS]
Safdar, Muhammad; et al. 고동적 범위와 넓은 색역을 포함하는 이미지 신호를 위한 지각적으로 균일한 색공간. 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 표준 - 마스터링 기준 디스플레이의 고동적 범위 전기-광학 전달 함수. 2014년 8월 29일. URL: https://pub.smpte.org/latest/st2084/st2084-2014.pdf

비규범적 참고문헌

[ARIB_STD-B67]
프로그램 제작을 위한 확장 이미지 동적 범위 텔레비전(EIDRTV) 시스템의 필수 매개변수 값. 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. 향상된 색상 균일성을 가진 색공간(IPT)의 개발 및 시험. 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]
CTS 1.2에 따른 DisplayHDR 사양 요약. 2024년 5월 17일. URL: https://displayhdr.org/performance-criteria/
[ISO_21496-1]
이미지 변환을 위한 게인 맵 메타데이터: Part 1: 동적 범위 변환. URL: https://www.iso.org/standard/86775.html
[Perrin]
Perrin, A-F.; et al. ICtCp 대 Y'CbCr: HDR 및 WCG를 위한 ICtCp 색공간과 적응형 리셰이퍼 평가. 2018년 5월. URL: https://ieeexplore.ieee.org/document/8333011
[Rec_BT.2124]
ITU-R BT.2124-0 텔레비전에서 색차의 잠재적 가시성 평가를 위한 객관적 메트릭. 2019년 1월. URL: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2124-0-201901-I!!PDF-E.pdf
[Rec_BT.814]
디스플레이의 밝기 및 명암 설정을 위한 PLUGE 테스트 신호와 정렬 절차의 사양. 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]
색상 볼륨 변환을 위한 동적 메타데이터 - 응용 #5(방송). 2025년. URL: https://github.com/SMPTE/st2094-50
[What_is_ICtCp]
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 Β 추가?