白点、色适应与编码
plt_convert 内部已经把这一切都处理好了 —— 它用 Bradford 把 D50 的 space 适应到 D65,并在途中解码
传递函数。这一页的函数把同样的零件暴露出来,好让你检视它们、手工复现一次转换,或者把它们组合成
plt_convert 做不到的东西。
这里没有任何函数会改变颜色的 space。唯一返回颜色的函数 plt_chromatic_adapt 保留 xyz 标签,只改
里面的数值。
白点
plt_white_points()
签名:plt_white_points() -> VARCHAR[]
全部白点名字:CIE 光源 a、b、c、d50、d55、d65、d75、e、f2、f7、f11,它们的
10° 观察者变体 d50_degree10、d55_degree10、d65_degree10、d75_degree10,以及 dci_p3
(影院白)。
SELECT plt_white_points() AS white_points;
plt_white_point_xyz(name)
签名:plt_white_point_xyz(name VARCHAR) -> DOUBLE[]
三刺激值 [X, Y, Z],已归一化到 Y = 1。这就是你从 D65 认出来的那组 [0.95047, 1, 1.08883]:
SELECT plt_white_point_xyz('d65') AS d65,
plt_white_point_xyz('d50') AS d50,
plt_white_point_xyz('a') AS illuminant_a;
plt_white_point_xy(name)
签名:plt_white_point_xy(name VARCHAR) -> DOUBLE[]
换成色度坐标 [x, y],即它在 CIE 1931 图上的位置:
SELECT plt_white_point_xy('d65') AS d65,
plt_white_point_xy('d50') AS d50;
名字会被规范化(D65、d-65、d 65 都能用),另外接受几个别名:illuminant_a …
illuminant_e,以及 10° 变体的 d65_10 / d65_10deg / d65_degree_10。
SELECT plt_white_point_xyz('d42');
色适应
plt_adaptation_methods()
签名:plt_adaptation_methods() -> VARCHAR[]
三种方法:bradford(常用的默认值,也是 plt_convert 用的)、von_kries 与 unit_matrix(纯粹的
XYZ 缩放,适合当基线)。别名如 vonkries、hpe、hunt_pointer_estevez、identity、none 与
xyz_scaling 也被接受。
SELECT plt_adaptation_methods() AS methods;
plt_adaptation_matrix(source, target, method)
签名:plt_adaptation_matrix(source VARCHAR, target VARCHAR, method VARCHAR) -> DOUBLE[]
把 source 下的 XYZ 值送到 target 下的 3×3 矩阵,行优先:
SELECT plt_adaptation_matrix('d65', 'd50', 'bradford') AS d65_to_d50,
plt_adaptation_matrix('a', 'c', 'bradford') AS a_to_c;
这个矩阵由三块拼成,每一块都单独暴露:plt_lms_matrix(method) → 增益 →
plt_lms_to_xyz_matrix(method)。因此可以搭一条自己的链条:
SELECT plt_lms_matrix('bradford') AS xyz_to_lms,
plt_diagonal_adaptation_matrix('d65', 'd50', 'bradford') AS gains,
plt_lms_to_xyz_matrix('bradford') AS lms_to_xyz;
plt_lms_matrix(method)
签名:plt_lms_matrix(method VARCHAR) -> DOUBLE[]
该方法对应的 XYZ→LMS 矩阵(Bradford、von Kries / Hunt-Pointer-Estevez,或基于单位矩阵的 unit matrix)。
plt_lms_to_xyz_matrix(method)
签名:plt_lms_to_xyz_matrix(method VARCHAR) -> DOUBLE[]
该方法对应的 LMS→XYZ 矩阵,即 plt_lms_matrix 的逆矩阵。
plt_diagonal_adaptation_matrix(source, target, method)
签名:plt_diagonal_adaptation_matrix(source VARCHAR, target VARCHAR, method VARCHAR) -> DOUBLE[]
两个白点之间的对角 LMS 增益矩阵。它只在两个 LMS 矩阵之间才有意义:
SELECT plt_diagonal_adaptation_matrix('d65', 'd50', 'bradford') AS gains;
plt_chromatic_adapt(color, target, method) 与 plt_chromatic_adapt(color, source, target, method)
签名:plt_chromatic_adapt(color plt_color, target VARCHAR, method VARCHAR) -> plt_color
签名:plt_chromatic_adapt(color plt_color, source VARCHAR, target VARCHAR, method VARCHAR) -> plt_color
把适应矩阵作用到一个颜色上。颜色必须处在 xyz,因为它的分量就是矩阵所作用的三刺激值。三参数
形式假定分量处在 D65 下;四参数形式显式给出源白点。
返回值的标签是 xyz,携带的是目标白点下的数值。白点本身并不是值的一部分,所以你得自己记住它 ——
plt_xyz 意味着 D65,而一个适应到 d50 的结果是同一个标签、不同的数值。
SELECT plt_chromatic_adapt(plt_xyz(0.5, 0.4, 0.3), 'd50', 'bradford') AS adapted,
plt_chromatic_adapt(plt_xyz(0.5, 0.4, 0.3), 'd65', 'd50', 'bradford') AS explicit_source;
SELECT plt_components(c) AS original,
plt_components(plt_chromatic_adapt(c, 'a', 'bradford')) AS under_a,
plt_components(c) AS still_original
FROM (SELECT plt_xyz(0.5, 0.4, 0.3) AS c);
用矩阵与 plt_apply_matrix 手工做同样的适应,得到的是同样的数值:
SELECT plt_components(plt_chromatic_adapt(c, 'd50', 'bradford')) AS adapted,
plt_components(plt_apply_matrix(plt_adaptation_matrix('d65', 'd50', 'bradford'), c)) AS by_hand
FROM (SELECT plt_xyz(0.5, 0.4, 0.3) AS c);
处在别的 space 的颜色会报错,而不是被隐式转换:
SELECT plt_chromatic_adapt(plt_srgb(1, 0, 0), 'd50', 'bradford');
SELECT plt_adaptation_matrix('d65', 'd50', 'cat02');
3x3 矩阵
矩阵永远是恰好九个值的 LIST(DOUBLE),行优先:
[m11, m12, m13, m21, m22, m23, m31, m32, m33]
plt_matrix_identity()
签名:plt_matrix_identity() -> DOUBLE[]
plt_matrix_scale(s1, s2, s3)
签名:plt_matrix_scale(s1 DOUBLE, s2 DOUBLE, s3 DOUBLE) -> DOUBLE[]
对角线上是这三个值的对角矩阵 —— 它独立缩放每个分量。
SELECT plt_matrix_identity() AS identity,
plt_matrix_scale(2, 0.5, 1) AS scale;
plt_matrix_multiply(a, b)
签名:plt_matrix_multiply(a DOUBLE[], b DOUBLE[]) -> DOUBLE[]
这个乘积先作用 a、再作用 b —— 即 palette 的 Matrix3::then 顺序。要「先适应再缩放」,就把
适应矩阵放在前面:
SELECT plt_matrix_multiply(plt_matrix_identity(), plt_matrix_scale(2, 2, 2)) AS scaled,
plt_matrix_multiply(plt_matrix_scale(2, 2, 2), plt_matrix_identity()) AS same;
plt_matrix_inverse(matrix)
签名:plt_matrix_inverse(matrix DOUBLE[]) -> DOUBLE[]
plt_matrix_apply(matrix, x, y, z)
签名:plt_matrix_apply(matrix DOUBLE[], x DOUBLE, y DOUBLE, z DOUBLE) -> DOUBLE[]
把矩阵作用到三个数上,返回三个结果 —— 不涉及颜色类型:
SELECT plt_matrix_apply(plt_matrix_scale(2, 3, 4), 1, 1, 1) AS scaled,
plt_matrix_apply(plt_matrix_inverse(plt_matrix_scale(2, 4, 0.5)), 2, 4, 0.5) AS back_to_one;
plt_apply_matrix(matrix, color)
签名:plt_apply_matrix(matrix DOUBLE[], color plt_color) -> plt_color
把矩阵作用到颜色在当前 space 里的三个分量上,保留 space 标签与 alpha。典型用法是 xyz 配一个
适应矩阵或三原色矩阵:
SELECT plt_components(plt_apply_matrix(plt_matrix_scale(0.5, 0.5, 0.5),
plt_xyz(0.4, 0.3, 0.2))) AS halved,
plt_space(plt_apply_matrix(plt_matrix_scale(0.5, 0.5, 0.5), plt_oklch(0.5, 0.1, 30))) AS still_oklch;
会报错的情况:列表不是九个数字,以及矩阵无法求逆:
SELECT plt_matrix_apply([1, 0, 0, 0, 1, 0], 1, 2, 3);
编码:传递函数、三原色与矩阵
plt_encoding_spaces()
签名:plt_encoding_spaces() -> VARCHAR[]
15 个 RGB space 名字加上三个 luma 名字 —— 也就是所有带传递函数的 space。
SELECT plt_encoding_spaces() AS spaces;
plt_transfer_function(space)
签名:plt_transfer_function(space VARCHAR) -> VARCHAR
某个 space 用的是哪个传递函数。编码变体与线性变体会给出不同答案:
SELECT plt_transfer_function('srgb') AS srgb,
plt_transfer_function('srgb_linear') AS srgb_linear,
plt_transfer_function('dci_p3') AS dci_p3,
plt_transfer_function('prophoto_rgb') AS prophoto,
plt_transfer_function('rec2020') AS rec2020;
plt_transfer_functions()
签名:plt_transfer_functions() -> VARCHAR[]
七个名字:linear、gamma_2_2、srgb、adobe_rgb、prophoto_rgb、p3_gamma、rec_oetf。
plt_decode(space, value)
签名:plt_decode(space VARCHAR, value DOUBLE) -> DOUBLE
用一个 已编码 的分量值,按该 space 的传递函数求出线性光。这就是每个 RGB 分量进入 XYZ 时经历的 那一步:
SELECT plt_decode('srgb', 0.5) AS half_encoded,
plt_decode('srgb', 1.0) AS one,
plt_decode('srgb_linear', 0.5) AS already_linear;
plt_encode(space, value)
签名:plt_encode(space VARCHAR, value DOUBLE) -> DOUBLE
反向操作:把一个线性值编回该 space 的编码。
SELECT plt_encode('srgb', 0.21404114048223255) AS back_to_half,
plt_encode('srgb', plt_decode('srgb', 0.25)) AS round_trip;
plt_white_point_of(space)
签名:plt_white_point_of(space VARCHAR) -> VARCHAR
某个 space 定义时参照的白点。它接受全部 44 个 space,不只是 RGB:
SELECT plt_white_point_of('srgb') AS srgb,
plt_white_point_of('prophoto_rgb') AS prophoto,
plt_white_point_of('xyz_d50') AS xyz_d50,
plt_white_point_of('dci_p3') AS dci_p3,
plt_white_point_of('oklch') AS oklch;
plt_rgb_primaries(space)
签名:plt_rgb_primaries(space VARCHAR) -> plt_color[]
某个 RGB space 的红、绿、蓝三原色,每个都是一个 yxy 颜色(色度加亮度),顺序就是红绿蓝。luma
space 名字也被接受,它们与 sRGB 共享三原色:
SELECT plt_rgb_primaries('srgb') AS primaries,
plt_components(plt_rgb_primaries('display_p3')[1]) AS p3_red;
plt_rgb_to_xyz_matrix(space)
签名:plt_rgb_to_xyz_matrix(space VARCHAR) -> DOUBLE[]
该 space 的 3×3 RGB→XYZ 矩阵,行优先。这是转换中的线性部分:
SELECT plt_rgb_to_xyz_matrix('srgb') AS srgb,
plt_rgb_to_xyz_matrix('rec2020') AS rec2020;
plt_xyz_to_rgb_matrix(space)
签名:plt_xyz_to_rgb_matrix(space VARCHAR) -> DOUBLE[]
逆矩阵,XYZ→RGB,由上面那个算出来:
SELECT plt_xyz_to_rgb_matrix('srgb') AS xyz_to_srgb;
用这些零件复现一次转换 —— 解码分量、作用矩阵,再与 plt_convert 对比:
SELECT plt_matrix_apply(plt_rgb_to_xyz_matrix('srgb'),
plt_decode('srgb', 1), plt_decode('srgb', 0.5), plt_decode('srgb', 0)) AS by_hand,
plt_components(plt_convert(plt_srgb(1, 0.5, 0), 'xyz')) AS converted;
没有三原色的 space 会报错:
SELECT plt_rgb_primaries('lab');
SELECT plt_decode('hsl', 0.5);