color

color

现代JavaScript颜色处理库 高效精准轻量级

@texel/color是一个现代JavaScript颜色处理库,为实时应用、生成艺术和网页图形提供高效解决方案。该库支持快速颜色转换、色差计算、色域映射和序列化,在速度和精确度方面表现出色。支持OKLCH、DisplayP3等现代颜色空间,并可通过tree-shaking优化包体积。相比其他类似库,性能提升5-125倍,内存占用更低。

@texel/color颜色库JavaScript色彩转换色域映射Github开源项目

@texel/color

生成的图片

这是一个简洁现代的JavaScript颜色库。特别适用于实时应用、生成艺术和网页图形。

  • 功能:快速颜色转换、色差计算、色域映射和序列化
  • 速度优化:比Colorjs.io快约5-125倍(参见基准测试
  • 内存和分配优化:转换和色域映射函数内不创建数组或对象
  • 优化打包体积:零依赖,未使用的色彩空间可自动被树摇除去,保持小体积(例如,如果只需要OKLCH到sRGB的转换,压缩后约3.5kb)
  • 精确度优化:高精度色彩空间矩阵
  • 专注于最小化和现代化的色彩空间集合:
    • xyz (D65)、xyz-d50、oklab、oklch、okhsv、okhsl、srgb、srgb-linear、display-p3、display-p3-linear、rec2020、rec2020-linear、a98-rgb、a98-rgb-linear、prophoto-rgb、prophoto-rgb-linear

安装

使用npm安装并导入模块。

npm install @texel/color --save

示例

将OKLCH(OKLab的圆柱形式)转换为sRGB:

import { convert, OKLCH, sRGB } from "@texel/color"; // L = 0 .. 1 // C = 0 .. 0.4 // H = 0 .. 360(度) const rgb = convert([0.5, 0.15, 30], OKLCH, sRGB); // 注意sRGB输出范围为0 .. 1 // -> [ 0.658, 0.217, 0.165 ]

你也可以使用通配符导入:

import * as colors from "@texel/color"; const rgb = colors.convert([0.5, 0.15, 30], colors.OKLCH, colors.sRGB);

:bulb: 现代打包工具(esbuild、vite)会应用树摇,移除未使用的功能,如代码中未引用的色彩空间和色域映射函数。上述脚本使用esbuild打包后约3.5kb。

另一个使用色域映射和序列化的宽色域Canvas2D示例:

import { gamutMapOKLCH, DisplayP3Gamut, sRGBGamut, serialize } from "@texel/color"; // 可能在或不在sRGB色域内的值 const oklch = [ 0.15, 0.425, 30 ]; // 决定要映射到哪个色域 const isDisplayP3Supported = /* 检查环境 */; const gamut = isDisplayP3Supported ? DisplayP3Gamut : sRGBGamut; // 将输入的OKLCH映射到R,G,B空间(sRGB或DisplayP3) const rgb = gamutMapOKLCH(oklch, gamut); // 获取输出空间的CSS颜色字符串 const color = serialize(rgb, gamut.space); // 在Canvas2D上下文中绘制颜色 const canvas = document.createElement('canvas'); const context = canvas.getContext('2d', { colorSpace: gamut.id }); context.fillStyle = color; context.fillRect(0,0, canvas.width, canvas.height);

API

output = convert(coords, fromSpace, toSpace, output = [0, 0, 0])

coords(通常为[r,g,b][l,c,h]等)从fromSpace转换到指定的toSpace。from和to空间是spaces接口之一。

你可以传入output,一个三维向量,结果将存储在其中。这可用于避免在热代码路径中分配新内存。

返回值是目标空间的新坐标;如sRGB空间的目标为[r,g,b]。注意,大多数空间使用归一化且无界的坐标;所以RGB空间的范围是0..1,可能会超出范围(即超出色域)。你可能需要结合gamutMapOKLCH使用,见下文。

output = gamutMapOKLCH(oklch, gamut = sRGBGamut, targetSpace = gamut.space, out = [0, 0, 0], mapping = MapToCuspL, [cusp])

执行Björn Ottoson描述的(2021)快速OKLCH色域映射。接受OKLCH空间的输入[l,c,h]坐标,确保最终结果在指定的颜色gamut内(默认sRGBGamut)。你可以进一步指定不同的目标空间(默认为色域的空间),例如获取线性光sRGB并避免传递函数,或保持结果在OKLCH中:

import { gamutMapOKLCH, sRGBGamut, sRGBLinear, OKLCH } from "@texel/color"; // 映射到sRGB但返回线性sRGB const lrgb = gamutMapOKLCH(oklch, sRGBGamut, sRGBLinear); // 或映射到sRGB但返回OKLCH(不执行RGB裁剪) const lch = gamutMapOKLCH(oklch, sRGBGamut, OKLCH);

你可以指定out数组以避免分配,结果将存储在该数组中。你还可以指定mapping函数,决定色域映射时使用的策略,可以是以下之一:

import { // 可能的映射 MapToL, MapToGray, MapToCuspL, MapToAdaptiveGray, MapToAdaptiveCuspL, } from "@texel/color"; // 执行sRGB色域映射时保持亮度 const rgb = [0, 0, 0]; gamutMapOKLCH(oklch, sRGBGamut, sRGB, rgb, MapToL);

cusp也可作为最后一个参数传入,允许对已知色相进行更快的评估。见下文计算cusp。

注意: 如果映射到基于OKLab的目标(OKLCH、OKHSL等),将跳过最后的RGB裁剪步骤。这会产生更可预测的OKLab和OKLCH结果,但在转换为可显示颜色时,你可能需要执行最后的clampedRGB()步骤。

LC = findCuspOKLCH(a, b, gamut, out = [0, 0])

找到给定OKLab色相平面(用OKLab空间中的归一化ab值表示)的'cusp',返回[L, C](亮度和色度)。当你在已知色相上工作时,这对预计算色域映射的某些方面很有用:

import { sRGBGamut, findCuspOKLCH, gamutMapOKLCH, degToRad, MapToCuspL, } from "@texel/color"; const gamut = sRGBGamut; // 为这个色相计算一次cusp const H = 30; // 例如30º色相 const hueAngle = degToRad(H); const a = Math.cos(hueAngle); const b = Math.sin(hueAngle); const cuspLC = findCuspOKLCH(a, b, gamut); // ... 在程序的其他地方 ... // 传入'cusp'参数以加快评估 // 假设你的OKLCH坐标与cusp有相同的色相(H) gamutMapOKLCH(oklch, gamut, gamut.space, out, MapToCuspL, cuspLC);

ab也可以来自OKLab坐标,但必须归一化使a^2 + b^2 == 1

str = serialize(coords, inputSpace, outputSpace = inputSpace)

将指定的coords(假定在inputSpace中)转换为字符串,如果需要,先转换到指定的outputSpace。如果空间是sRGB,为了浏览器兼容性和性能,将使用普通的rgb(r,g,b)字符串(字节形式),否则将返回CSS颜色字符串。注意,并非所有空间(如某些线性空间)目前都受CSS支持。你可以选择在coords数组中传入第四个元素作为alpha分量(0..1范围)。

import { serialize, sRGB, DisplayP3, OKLCH } from "@texel/color"; serialize([0, 0.5, 1], sRGB); // "rgb(0, 128, 255)" serialize([0, 0.5, 1, 0.5], sRGB); // "rgba(0, 128, 255, 0.5)" serialize([0, 0.5, 1], DisplayP3); // "color(display-p3 0 0.5 1)" serialize([0, 0.5, 1, 0.35], DisplayP3); // "color(display-p3 0 0.5 1 / 0.35)" serialize([1, 0, 0], OKLCH, sRGB); // "rgb(255, 255, 255)" serialize([1, 0, 0], OKLCH); // "oklch(1 0 0)"

info = deserialize(colorString)

这是serialize的反向操作,它会接收一个字符串,确定它引用的色彩空间id,以及3个或4个(含透明度)coords。这个功能有意地限制了范围,只支持十六进制RGB、rgb()rgba()字节值,以及oklch()oklab()和不带修饰符的普通color()函数。

import { deserialize } from "@texel/color"; const { coords, id } = deserialize("color(display-p3 0 0.5 1 / 0.35)"); console.log(id); // "display-p3" console.log(coords); // [ 0, 0.5, 1, 0.35 ]

注意: 解析仍然是API设计中正在进行的工作,复杂的CSS颜色字符串处理不在本库的范围内。

delta = deltaEOK(oklabA, oklabB)

在OKLab空间中计算两个坐标之间的颜色差异。由于这是一个感知均匀的色彩空间,改进了CIELAB及其缺陷,因此在许多情况下它应该可以适当地替代CIEDE2000颜色差异方程。

[utils]

该模块还导出了许多其他实用工具

色彩空间

该模块导出了一组色彩空间:

import { XYZ, // 使用D65白点 XYZD50, // 使用D50白点 sRGB, sRGBLinear, DisplayP3, DisplayP3Linear, Rec2020, Rec2020Linear, A98RGB, // Adobe® 1998 RGB A98RGBLinear, ProPhotoRGB, ProPhotoRGBLinear, OKLab, OKLCH, OKHSL, // 在sRGB色域内 OKHSV, // 在sRGB色域内 // 列出所有空间的函数 listColorSpaces, } from "@texel/color"; console.log(listColorSpaces()); // [XYZ, sRGB, sRGBLinear, ...] console.log(sRGBLinear.id); // "srgb-linear" console.log(sRGB.base); // -> sRGBLinear console.log(sRGB.fromBase(someLinearRGB)); // -> [gamma编码的sRGB...] console.log(sRGB.toBase(someGammaRGB)); // -> [线性sRGB...]

注意,并非所有空间都有base字段;如果未指定,则假定色彩空间可以通过OKLab或XYZ作为根进行传递。

色域

该模块导出了一组"色域",这些色域是由OKLab空间中的近似值定义的边界,允许快速进行色域映射。这些接口主要由gamutMapOKLCH函数使用。

import { sRGBGamut, DisplayP3Gamut, Rec2020Gamut, A98RGBGamut, // 列出所有色域的函数 listColorGamuts, } from "@texel/color"; console.log(listColorGamuts()); // [sRGBGamut, ...] console.log(sRGBGamut.space); // sRGB空间 console.log(sRGBGamut.space.id); // 'srgb'

注意:目前尚不支持ProPhoto色域,我欢迎通过Python脚本修复它的PR。

实用工具

除了核心API外,该模块还导出了许多实用工具:

b = floatToByte(f)

将0..1范围内的浮点数转换为0..255范围内的字节,进行四舍五入并限制在范围内。

out = XYZ_to_xyY(xyz, out=[0,0,0])

将XYZ坐标转换为xyY形式,如果指定了out,则将结果存储在其中后返回。

out = xyY_to_XYZ(xyY, out=[0,0,0])

将xyY坐标转换为XYZ形式,如果指定了out,则将结果存储在其中后返回。

v = lerp(min, max, t)

使用因子t在min和max之间执行线性插值。

v = lerpAngle(min, max, t)

使用因子t在min和max之间执行圆形线性插值,其中min和max被视为角度(以度为单位),允许值在0到360之间环绕,插值以创建最短的弧。

c = clamp(value, min, max)

value限制在min和max之间,并返回结果。

out = clampedRGB(inRGB, out=[0,0,0])

将RGB限制(即裁剪)在0..1范围内,如果指定了out,则将结果存储在其中后返回。

inside = isRGBInGamut(rgb, epsilon = 0.000075)

如果给定的rgb在其0..1色域边界内,则返回true,阈值为epsilon

rgb = hexToRGB(hex, out=[0,0,0])

将指定的十六进制字符串(带或不带前导#)转换为0..1范围内的浮点RGB三元组,如果指定了out,则将结果存储在其中后返回。

hex = RGBToHex(rgb)

将指定的RGB三元组(0..1范围内的浮点数)转换为带前导#的6字符十六进制颜色字符串。

angle = constrainAngle(angle)

angle(以度为单位)限制在0..360范围内,必要时进行环绕。

degAngle = radToDeg(radAngle)

将角度(以弧度为单位)转换为度。

radAngle = degToRad(degAngle)

将角度(以度为单位)转换为弧度。

变换矩阵

您还可以导入更低级别的函数和矩阵;这可能对细粒度转换有用,或者例如将缓冲区上传到WebGPU以进行计算着色器。

import { OKLab_to, OKLab_from, transform, XYZ_to_linear_sRGB_M, LMS_to_XYZ_M, XYZ_to_LMS_M, sRGB, OKHSLToOKLab, DisplayP3Gamut, } from "@texel/color"; console.log(XYZ_to_linear_sRGB_M); // [ [a,b,c], ... ] OKLab_to(oklab, LMS_to_XYZ_M); // OKLab -> XYZ D65 OKLab_from(xyzD65, XYZ_to_LMS_M); // XYZ D65 -> OKLab transform(xyzD65, XYZ_to_linear_sRGB_M); // XYZ D65 -> sRGBLinear sRGB.fromBase(in_linear_sRGB, out_sRGB); // 线性到gamma传递函数 sRGB.toBase(in_sRGB, out_linear_sRGB); // gamma到线性传递函数 // 非sRGB色域中的OKHSL // 另见OKHSVToOKLab及其反函数 OKHSLToOKLab([h, s, l], DisplayP3Gamut, optionalOutVec);

插值

该库目前只公开了{ lerp, lerpAngle }函数。要插值颜色,您需要构建一些额外的逻辑,例如,请参见example-interpolation.js脚本,该脚本在Canvas2D中创建颜色渐变。

自定义色彩空间

您可以构建自定义色彩空间对象来扩展这个库,例如添加对CIELab和HSL的支持。有关示例,请参见test/spaces/lab.jstest/spaces/hsl.js。其中一些空间可能在以后添加到库中,尽管当前重点是"现代"空间(如OKLab,它在很大程度上使CIELab和HSL过时)。自定义色彩空间的文档正在编写中。

注意事项

为什么要开发另一个库?

Colorjs非常出色,可能是JavaScript中当前领先的标准,但它对于创意编码和实时Web应用程序来说并不是很实用,在这些应用程序中,要求通常是(1)更精简的代码库,(2)高度优化,以及(3)最小化GC抖动。

Colorjs,以及类似的Culori,专注于匹配CSS规范,这意味着它很可能会随着时间的推移继续增加复杂性,性能通常会受到影响(例如,@texel/color的尖点交叉色域映射比Colorjs快约125倍,比culori快约60倍)。 还有许多其他选项,如 color-spacecolor-convert,但这些不支持现代色彩空间,如 OKLab 和 OKHSL,和/或具有可疑的准确度(例如,许多库不区分 XYZ 中的 D50 和 D65 白点)。

支持的色彩空间

本库并不旨在涵盖所有色彩空间;它只专注于有限的"现代"集合,即 OKLab、OKHSL 和 DeltaEOK 在许多实际用途中已经取代了 CIELab、HSL 和 CIEDE2000,使得本库更简单、更精简。请注意,其他空间如 CIELab 和 HSL 可通过"自定义色彩空间"得到支持。

改进与技术

该模块使用了以下一些做法,以显著优化性能并减小打包体积:

  • 循环、闭包、解构和其他语法糖被替换为更优化的代码路径和简单的数组访问。
  • 移除了热点代码路径中的内存分配,必要时重复使用临时数组。
  • 某些转换,如 OKLab 到 sRGB,不需要先通过 XYZ,可以使用已知矩阵直接转换。
  • API 设计的结构使得色彩空间通常不在内部引用,允许它们自动进行树摇。

准确度

所有转换都经过测试,与 Colorjs 转换近似相等,误差在 2<sup>-33</sup>(10 位小数)以内,在某些情况下甚至更准确。

本库使用 coloraide 及其 Python 工具计算转换矩阵和 OKLab 色域近似值。一些矩阵已硬编码到脚本中,并尽可能使用有理数(如 CSS 颜色模块工作草案规范建议 的那样)。

如果您认为矩阵或准确度可以改进,请提交 PR。

基准测试

test 目录中有几个基准测试:

以下结果基于 MacBook Air M2。请注意,Colorjs 的性能取决于您使用的 API(默认的基于类的 API 比过程式 API 慢得多)。

<details> <summary>与 Colorjs.io 的基准对比</summary>
转换(Colorjs.io 过程式 API)--
Colorjs.io:2955.88 毫秒
我们的:457.86 毫秒
加速:快 6.5 倍

转换(Colorjs.io 主要 API)--
Colorjs.io:10034.38 毫秒
我们的:452.11 毫秒
加速:快 22.2 倍

OKLCH - sRGB 色域映射(Colorjs.io 过程式 API)--
Colorjs.io:5602.46 毫秒
我们的:49.10 毫秒
加速:快 114.1 倍

OKLCH - sRGB 色域映射(Colorjs.io 主要 API)--
Colorjs.io:5913.80 毫秒
我们的:44.91 毫秒
加速:快 131.7 倍

所有空间到 P3 的色域映射(Colorjs.io 过程式 API)--
Colorjs.io:4693.43 毫秒
我们的:150.16 毫秒
加速:快 31.3 倍

所有空间到 P3 的色域映射(Colorjs.io 主要 API)--
Colorjs.io:5478.16 毫秒
我们的:145.88 毫秒
加速:快 37.6 倍
</details> <details> <summary>与 Culori 的基准对比</summary>
使用输入类型:OKLab L 平面的随机采样进行测试
OKLCH 到 P3 的转换 --
Culori:43.30 毫秒
我们的:12.83 毫秒
加速:快 3.4 倍

OKLCH 到 P3 色域的色域映射 --
Culori:1588.62 毫秒
我们的:23.05 毫秒
加速:快 68.9 倍
</details>

本地运行

克隆,npm install,然后运行 npm run 列出可用的脚本,或运行 npm t 执行测试。

致谢

这个库的实现得益于许多开发者和工程师的出色前期工作:

许可

MIT 许可,详见 LICENSE.md

编辑推荐精选

Vora

Vora

免费创建高清无水印Sora视频

Vora是一个免费创建高清无水印Sora视频的AI工具

Refly.AI

Refly.AI

最适合小白的AI自动化工作流平台

无需编码,轻松生成可复用、可变现的AI自动化工作流

酷表ChatExcel

酷表ChatExcel

大模型驱动的Excel数据处理工具

基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。

AI工具酷表ChatExcelAI智能客服AI营销产品使用教程
TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
AIWritePaper论文写作

AIWritePaper论文写作

AI论文写作指导平台

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

AI辅助写作AI工具AI论文工具论文写作智能生成大纲数据安全AI助手热门
博思AIPPT

博思AIPPT

AI一键生成PPT,就用博思AIPPT!

博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。

AI办公办公工具AI工具博思AIPPTAI生成PPT智能排版海量精品模板AI创作热门
潮际好麦

潮际好麦

AI赋能电商视觉革命,一站式智能商拍平台

潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。

iTerms

iTerms

企业专属的AI法律顾问

iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。

SimilarWeb流量提升

SimilarWeb流量提升

稳定高效的流量提升解决方案,助力品牌曝光

稳定高效的流量提升解决方案,助力品牌曝光

Sora2视频免费生成

Sora2视频免费生成

最新版Sora2模型免费使用,一键生成无水印视频

最新版Sora2模型免费使用,一键生成无水印视频

下拉加载更多