Electron ColorSpace 对象参考:四维色彩空间描述符及其在共享纹理、离屏渲染中的源码实现
本文系统梳理 Electron API 中的 ColorSpace 结构对象:完整覆盖其 primaries、transfer、matrix、range 四个字段的全部取值、sRGB / Display P3 / HDR10 / HLG 等标准与 HDR 色彩空间定义,并结合 Electron 源码中的 gin 类型转换器、nativeImage.toBitmap()、sharedTexture 模块与 Offscreen Rendering(OSR)实现,说明该对象在进程间色彩信息传递中的真实调用链与默认值行为,帮助你在做视频纹理导入、位图导出和离屏渲染时精确控制色彩语义。
ColorSpace 对象的结构
ColorSpace 是 Electron API 文档中的一个结构对象(structure),用于在 API 层描述一个完整的色彩空间。它由四个字符串字段组成,每个字段都是受限枚举值:
| 字段 | 含义 |
|---|---|
primaries |
色彩空间的主色(color primaries),定义红/绿/蓝三原色在 CIE 色度图中的位置 |
transfer |
传输函数(transfer function),定义信号值与相对亮度之间的映射关系 |
matrix |
色彩矩阵(color matrix),定义颜色分量到亮度/色度分量的线性变换 |
range |
色彩范围(color range),定义采样值的实际数值区间 |
这四个维度共同对应 Chromium 中 ui/gfx/color_space.h 提供的 gfx::ColorSpace 类——从源码结构看,Electron 的 ColorSpace 对象本质上是 gfx::ColorSpace 在 V8 值层的序列化形式,由通用类型转换器负责双向映射(见下文 gin 转换器实现)。
primaries 字段取值
primaries string - 色彩空间的主色,可取以下值:
bt709- BT709 primaries(也用于 sRGB)bt470m- BT470M primariesbt470bg- BT470BG primariessmpte170m- SMPTE170M primariessmpte240m- SMPTE240M primariesfilm- Film primariesbt2020- BT2020 primariessmptest428-1- SMPTEST428-1 primariessmptest431-2- SMPTEST431-2 primariesp3- P3 primariesxyz-d50- XYZ D50 primariesadobe-rgb- Adobe RGB primariesapple-generic-rgb- Apple Generic RGB primarieswide-gamut-color-spin- Wide Gamut Color Spin primariesebu-3213-e- EBU 3213-E primariescustom- 自定义 primariesinvalid- 无效的 primaries
transfer 字段取值
transfer string - 色彩空间的传输函数,可取以下值:
bt709- BT709 transfer functionbt709-apple- BT709 Apple transfer functiongamma18- Gamma 1.8 transfer functiongamma22- Gamma 2.2 transfer functiongamma24- Gamma 2.4 transfer functiongamma28- Gamma 2.8 transfer functionsmpte170m- SMPTE170M transfer functionsmpte240m- SMPTE240M transfer functionlinear- Linear transfer functionlog- Log transfer functionlog-sqrt- Log Square Root transfer functioniec61966-2-4- IEC61966-2-4 transfer functionbt1361-ecg- BT1361 ECG transfer functionsrgb- sRGB transfer functionbt2020-10- BT2020-10 transfer functionbt2020-12- BT2020-12 transfer functionpq- PQ(Perceptual Quantizer)transfer functionsmptest428-1- SMPTEST428-1 transfer functionhlg- HLG(Hybrid Log-Gamma)transfer functionsrgb-hdr- sRGB HDR transfer functionlinear-hdr- Linear HDR transfer functioncustom- 自定义传输函数custom-hdr- 自定义 HDR 传输函数scrgb-linear-80-nits- scRGB Linear 80 nits transfer functioninvalid- 无效的传输函数
matrix 字段取值
matrix string - 色彩空间的色彩矩阵,可取以下值:
rgb- RGB 矩阵bt709- BT709 矩阵fcc- FCC 矩阵bt470bg- BT470BG 矩阵smpte170m- SMPTE170M 矩阵smpte240m- SMPTE240M 矩阵ycocg- YCoCg 矩阵bt2020-ncl- BT2020 NCL 矩阵ydzdx- YDzDx 矩阵gbr- GBR 矩阵invalid- 无效的矩阵
range 字段取值
range string - 色彩空间的取值范围,可取以下值:
limited- 限制范围(RGB 值从 16 到 235)full- 完整范围(RGB 值从 0 到 255)derived- 范围由传输函数和矩阵共同推导定义invalid- 无效范围
常用 ColorSpace 定义
Electron 文档给出了一组可直接复用的标准定义,按用途分为三类。
标准色彩空间
sRGB:
const cs = {
primaries: 'bt709',
transfer: 'srgb',
matrix: 'rgb',
range: 'full'
}
Display P3:
const cs = {
primaries: 'p3',
transfer: 'srgb',
matrix: 'rgb',
range: 'full'
}
XYZ D50:
const cs = {
primaries: 'xyz-d50',
transfer: 'linear',
matrix: 'rgb',
range: 'full'
}
HDR 色彩空间
Extended sRGB(将 sRGB 扩展到所有实数域):
const cs = {
primaries: 'bt709',
transfer: 'srgb-hdr',
matrix: 'rgb',
range: 'full'
}
scRGB Linear(全实数域线性传输函数):
const cs = {
primaries: 'bt709',
transfer: 'linear-hdr',
matrix: 'rgb',
range: 'full'
}
scRGB Linear 80 Nits(SDR 白电平为 80 nits):
const cs = {
primaries: 'bt709',
transfer: 'scrgb-linear-80-nits',
matrix: 'rgb',
range: 'full'
}
HDR10(BT.2020 主色 + PQ 传输函数):
const cs = {
primaries: 'bt2020',
transfer: 'pq',
matrix: 'rgb',
range: 'full'
}
HLG(BT.2020 主色 + HLG 传输函数):
const cs = {
primaries: 'bt2020',
transfer: 'hlg',
matrix: 'rgb',
range: 'full'
}
视频色彩空间
Rec. 601(SDTV):
const cs = {
primaries: 'smpte170m',
transfer: 'smpte170m',
matrix: 'smpte170m',
range: 'limited'
}
Rec. 709(HDTV):
const cs = {
primaries: 'bt709',
transfer: 'bt709',
matrix: 'bt709',
range: 'limited'
}
JPEG(JPEG 图片的典型色彩空间):
const cs = {
primaries: 'bt709',
transfer: 'srgb',
matrix: 'smpte170m',
range: 'full'
}
从源码结构看,"主色/传输函数"组合决定色彩域与色调映射语义,"矩阵"决定分量间如何混色,"范围"决定 8-bit 采样值的实际映射区间——例如视频流普遍使用 limited 范围(16–235),而 sRGB 图形内容使用 full 范围(0–255),这也是 Rec. 601/709 定义与 sRGB 定义的关键差异之一。
在 Electron API 中的使用场景
ColorSpace 对象本身不是独立的顶层 API,而是作为若干图形相关 API 的输入/输出参数出现。仓库文档中引用它的接口主要有三处:
nativeImage.toBitmap(options)
native-image 的 toBitmap() 方法接受 scaleFactor 与 colorSpace 两个选项,指定导出位图时使用的色彩空间。源码实现见 electron_api_native_image.cc:
v8::Local<v8::Value> NativeImage::ToBitmap(gin::Arguments* args) {
// ...
float scale = 1.0f;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
gin_helper::Dictionary options;
if (args->GetNext(&options)) {
options.Get("scaleFactor", &scale);
options.Get("colorSpace", &color_space);
}
const auto src = image_.AsImageSkia().GetRepresentation(scale).GetBitmap();
const auto dst_info = SkImageInfo::MakeN32Premul(
src.dimensions(), color_space.ToSkColorSpace());
// ... readPixels 将像素转换到目标色彩空间后写入 ArrayBuffer
}
要点:
- 不传
colorSpace时默认使用gfx::ColorSpace::CreateSRGB(),即上文的 sRGB 定义; - 传入的
ColorSpace对象经 gin 转换器解析为gfx::ColorSpace后,通过ToSkColorSpace()交给 Skia 的readPixels()完成色彩转换——也就是说,位图导出时会真实发生色彩空间变换,而不是仅仅携带元数据。
sharedTexture.importSharedTexture(options)
shared-texture 模块(实验性 API)支持把平台相关的共享纹理句柄导入为 VideoFrame。其参数结构 SharedTextureImportTextureInfo 中的 colorSpace 字段为可选,用于描述纹理的色彩空间,与 pixelFormat(bgra / rgba / rgbaf16 / nv12 / nv16 / p010le)配合使用——对 10-bit YUV 这类 HDR 格式,colorSpace(如 HDR10 的 bt2020 + pq)是解码器正确还原色彩所必需的元数据。
源码见 electron_api_shared_texture.cc:
// The color space of the video frame.
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
即缺省回落到 sRGB;解析处(L640)通过 dict.Get("colorSpace", &out->color_space) 直接复用下文要介绍的 Converter<gfx::ColorSpace>::FromV8。解析后的色彩空间随后被写入 VideoFrame(L259 的 raw_frame->set_color_space(...))并用于创建 SharedImage(L771-L800),保证纹理在 WebGPU/渲染管线中的色彩语义与源帧一致。
Offscreen Rendering 的 OffscreenSharedTexture
开启 offscreen: true 时,web-contents 的 'render-process-gone' 之外还有离屏纹理输出通道:OffscreenSharedTexture 的 textureInfo 中包含 colorSpace 字段,描述当前视频帧的色彩空间。该字段由 OSR 层填充:osr_paint_event.h 中携带 gfx::ColorSpace color_space,经 osr_converter.cc 的 dict.Set("colorSpace", val.color_space) 序列化为 ColorSpace 对象交给 JS 侧。
源码实现:JS 字符串如何映射为 gfx::ColorSpace
ColorSpace 对象与 Chromium 类型之间的双向转换集中在 gfx_converter.cc,这是理解该结构行为的关键:
序列化方向(C++ → JS):ToV8
Converter<gfx::ColorSpace>::ToV8(L237-L439)通过四组 switch 语句分别把 GetPrimaryID()、GetTransferID()、GetMatrixID()、GetRangeID() 枚举映射为文档所列的字符串字面量(如 PrimaryID::BT709 -> "bt709"、TransferID::PQ -> "pq"、RangeID::LIMITED -> "limited"),最终生成含 primaries / transfer / matrix / range 四个键的 JS 字典。文档中列出的每一个取值都能在此处找到对应的枚举分支。
反序列化方向(JS → C++):FromV8 的默认值与边界行为
Converter<gfx::ColorSpace>::FromV8(L441-L594)有三个值得注意的实现事实:
-
默认值与 sRGB 一致。任何字段缺省时均回落到:
// Default values if not specified gfx::ColorSpace::PrimaryID primaries = gfx::ColorSpace::PrimaryID::BT709; gfx::ColorSpace::TransferID transfer = gfx::ColorSpace::TransferID::SRGB; gfx::ColorSpace::MatrixID matrix = gfx::ColorSpace::MatrixID::RGB; gfx::ColorSpace::RangeID range = gfx::ColorSpace::RangeID::FULL;因此一个空对象
{}等价于文档中的 sRGB 定义。 -
custom取值不支持反序列化。虽然ToV8能输出custom(primaries)与custom/custom-hdr(transfer),但FromV8在遇到这些字符串时会抛出TypeError("'custom' not supported."/"'custom', 'custom-hdr' not supported.",L457-L462、L500-L504)。也就是说,自定义色彩空间只能作为输出元数据被读取,不能作为 API 输入构造。 -
未知字符串落到
invalid。未被识别的值(而非custom)不会抛错,而是映射到INVALID枚举,最终构造出无效的gfx::ColorSpace(L592 的*out = gfx::ColorSpace(primaries, transfer, matrix, range))。使用时应以文档列出的枚举为准。
实践建议
- 图形内容默认 sRGB:
nativeImage.toBitmap()不传colorSpace即为 sRGB;如需导出到宽色域工作流(如 P3 校色),传入{ primaries: 'p3', transfer: 'srgb', matrix: 'rgb', range: 'full' }即可让 Skia 在导出时完成转换。 - HDR 纹理导入务必显式指定:使用
sharedTexture.importSharedTexture()导入p010le(BT.2020 10-bit YUV)等 HDR 格式时,colorSpace应显式给出 HDR10(bt2020+pq)或 HLG(bt2020+hlg)定义,否则按 sRGB 处理会导致色调与色域错误;SDR 视频则可用 Rec. 709limited定义。 - 区分
limited与full:广播电视素材(Rec. 601/709)使用limited(16–235),桌面图形内容使用full(0–255),混用会造成对比度与黑场偏差。 - 注意 API 成熟度:
sharedTexture模块在文档中明确标注为 Experimental(可能在未来版本移除或变更),其colorSpace相关用法适用前提是该模块在当前 Electron 版本可用;相关行为可通过 api-shared-texture-spec.ts、api-native-image-spec.ts 等测试文件在仓库中进一步验证。
参考文档与源码索引
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00