跳到主要内容

转换与夹紧

转换始终让空间标签与 alpha 保持一致:plt_convert(c, 'lab') 之后值里的空间是 lab, plt_convert(..., 'srgb') 又能把它带回来。数学由 palette 完成;这个扩展只负责选路线。

plt_convert(color, space)​

签名:plt_convert(color plt_color, space VARCHAR) -> plt_color

转换到目标空间,不做色域夹紧。超出目标范围的值原样返回,这对检查中间结果、以及那些本应可逆的 转换很有用。

SELECT plt_to_hex(plt_srgb(1, 0.5, 0)) AS srgb,
plt_components(plt_convert(plt_srgb(1, 0.5, 0), 'oklch')) AS as_oklch,
plt_components(plt_convert(plt_srgb(1, 0.5, 0), 'xyz')) AS as_xyz;

alpha 是复制过去的,不参与转换:

SELECT plt_convert(plt_with_alpha(plt_srgb(1, 0, 0), 0.25), 'lab') AS converted,
plt_alpha(plt_convert(plt_with_alpha(plt_srgb(1, 0, 0), 0.25), 'lab')) AS alpha;

plt_convert_clamped(color, space)​

签名:plt_convert_clamped(color plt_color, space VARCHAR) -> plt_color

先转换,再把结果夹进目标空间的标准范围。渲染之前你要的就是它:sRGB 之外的颜色会被拉回最接近的 色域内 sRGB 颜色,而不是得到 1.5 或 -0.3 这样的分量。

SELECT plt_components(plt_convert(plt_lab(50, 200, 200), 'srgb')) AS unclamped,
plt_components(plt_convert_clamped(plt_lab(50, 200, 200), 'srgb')) AS clamped;

plt_clamp(color)​

签名:plt_clamp(color plt_color) -> plt_color

在颜色自身的空间里夹紧,不做转换。Lab 的 a* 与 b* 停在 ±127,RGB 分量停在 0..1,但色相不会被 这个函数强行限制在 0..360。

SELECT plt_components(plt_lab(50, 200, 200)) AS out_of_range,
plt_components(plt_clamp(plt_lab(50, 200, 200))) AS clamped,
plt_components(plt_srgb(-0.2, 1.4, 0.5)) AS out_of_gamut,
plt_components(plt_clamp(plt_srgb(-0.2, 1.4, 0.5))) AS in_gamut;

plt_is_within_bounds(color)​

签名:plt_is_within_bounds(color plt_color) -> BOOLEAN

plt_clamp 是否会改变任何东西。把它和 WHERE 子句结合起来,就能找出渲染器不得不裁剪的颜色。

SELECT plt_is_within_bounds(plt_lab(50, 200, 200)) AS lab_ok,
plt_is_within_bounds(plt_clamp(plt_lab(50, 200, 200))) AS clamped_ok,
plt_is_within_bounds(plt_srgb(1, 0, 0)) AS srgb_ok;
SELECT c, plt_is_within_bounds(c) AS in_gamut
FROM (VALUES
(plt_srgb(0.2, 0.4, 0.6)),
(plt_srgb(-0.1, 0.5, 0.5)),
(plt_lch(50, 120, 40))
) t(c);

一次转换走哪条路线?​

所有转换都经过 XYZ (D65) —— palette 转换图的中心节点。编码的 RGB 空间会先被解码;D50 空间 (ProPhoto RGB、xyz_d50)用 Bradford 做色适应;CAM16 使用 palette 的默认观察条件。路线不由你选择, 但 plt_convert 与 plt_convert_clamped 在它上面算出的数字相同,而且经过任何可逆空间往返一次, 都能把原色还原到浮点精度:

SELECT plt_to_hex(plt_convert(plt_convert(plt_srgb(0.2, 0.4, 0.6), 'hsluv'), 'srgb')) AS round_trip;

一维的 luma* 空间按设计不可逆,而 srgb_gamma 是 palette 已废弃的伽马 2.2 编码 —— 除非你确实需要 它,否则用 plt_srgb。

plt_equals(a, b)​

签名:plt_equals(a plt_color, b plt_color) -> BOOLEAN

两个颜色渲染出来是否相同:都先转成 sRGB、每个通道量化到 8 位,alpha 保留两位小数。这就是 tinycolor 的 equals,比较来自不同 space 的颜色时通常正是你想要的结果 —— plt_srgb(1, 0, 0) 与 plt_hsl(0, 1, 0.5) 相等。感知均匀空间里可能差一丝的颜色,在这里也算相等:

SELECT plt_equals(plt_srgb(1, 0, 0), plt_hsl(0, 1, 0.5)) AS across_spaces,
plt_equals(plt_with_alpha(plt_srgb(1, 0, 0), 0.5), plt_with_alpha(plt_srgb(1, 0, 0), 0.6)) AS alpha_differs,
plt_equals(plt_srgb(0.5, 0.5, 0.5), plt_srgb(0.501, 0.5, 0.5)) AS within_a_byte;

直接用 = 比较两个 STRUCT 并不会这样:它会连 space 标签和完整的浮点分量一起比较,所以两个渲染 一致、只在最后一位上不同的 srgb 值在那里是 !=。

错误​

未知的空间名会让语句失败;错误信息里带函数名:

SELECT plt_convert(plt_srgb(1, 0, 0), 'nope');
SELECT plt_convert_clamped(plt_srgb(1, 0, 0), 'not-a-space');