換與感知調(diào)色實(shí)戰(zhàn)指南:基于 Tilt 倉(cāng)庫(kù)的深度解析)
開(kāi)發(fā)工具云原生微服務(wù)【免費(fèi)下載鏈接】tiltDefine your dev environment as code. For microservice apps on Kubernetes.項(xiàng)目地址https://gitcode.com/gh_mirrors/tilt/tilt點(diǎn)擊查看免費(fèi)下載導(dǎo)讀go-colorful 是一款為 Go 語(yǔ)言設(shè)計(jì)的顏色處理庫(kù)它在內(nèi)部以 sRGB標(biāo)準(zhǔn) RGB存儲(chǔ)顏色并提供 RGB、HSL、HSV、Hex、線性 RGB、CIE-XYZ、CIE-xyY、CIE-L*a*b*、CIE-L*u*v* 以及 CIE-L*C*h°HCL等多種顏色空間之間的轉(zhuǎn)換方法同時(shí)完整實(shí)現(xiàn) Go 標(biāo)準(zhǔn)庫(kù)image/color.Color接口。本文以該庫(kù)在 Tilt 項(xiàng)目中的實(shí)際引入v1.0.2聲明于 go.mod 與 vendor/modules.txt為背景從安裝、基礎(chǔ)用法、顏色距離計(jì)算、混合漸變、隨機(jī)調(diào)色、調(diào)色板生成到性能優(yōu)化與 FAQ 排障系統(tǒng)講解如何用它在 Go 中實(shí)現(xiàn)感知均勻的顏色計(jì)算與生成讀完即可在自己的微服務(wù)、CLI、游戲或數(shù)據(jù)可視化項(xiàng)目中直接落地使用。go-colorful 是什么為什么需要它Tilt 項(xiàng)目將 go-colorful 作為 vendor 依賴引入版本 v1.0.2屬于間接依賴它解決的問(wèn)題在社區(qū)中由來(lái)已久當(dāng)我們?cè)诔绦蛑行枰S機(jī)給用戶分配顏色、在兩個(gè)顏色之間做平滑過(guò)渡、或者生成一組彼此可區(qū)分的調(diào)色板時(shí)如果直接使用 RGB 空間進(jìn)行操作結(jié)果往往不自然——RGB 描述的是屏幕如何產(chǎn)生顏色而不是人類如何感知顏色。go-colorful 的核心思路見(jiàn) vendor/github.com/lucasb-eyer/go-colorful/colors.go是內(nèi)部統(tǒng)一用Color{R, G, B float64}結(jié)構(gòu)體存儲(chǔ) sRGB 值取值范圍[0..1]以 sRGB 為中樞向外輻射出多種顏色空間的正反向轉(zhuǎn)換函數(shù)提供顏色距離distance、混合blend、隨機(jī)顏色與調(diào)色板生成等高級(jí)功能。該庫(kù)支持的顏色空間及其取值范圍總結(jié)如下均來(lái)自原文檔顏色空間取值范圍說(shuō)明RGBR、G、B 均在 [0..1]內(nèi)部存儲(chǔ)格式HSLH 在 [0..360]S 與 L 在 [0..1]作者標(biāo)注legacy 原因保留HSVH 在 [0..360]S 與 V 在 [0..1]建議優(yōu)先使用 HCL 代替Hex RGB如#FF00FF互聯(lián)網(wǎng)顏色格式Linear RGB無(wú)固定范圍用于伽馬校正渲染CIE-XYZ幾乎在 [0..1]CIE 標(biāo)準(zhǔn)顏色空間CIE-xyYx、y、Y 均在 [0..1]色度編碼在 x/y亮度在 YCIE-L*a*b*L* 在 [0..1]a*、b* 幾乎在 [-1..1]感知均勻空間距離有意義CIE-L*u*v*L* 在 [0..1]u*、v* 幾乎在 [-1..1]與 Lab 類似無(wú)統(tǒng)一共識(shí)CIE-L*C*h°HCLH° 在 [0..360]C* 幾乎在 [-1..1]L* 同 LabLab 的極坐標(biāo)形式更好的 HSV幾乎在某個(gè)范圍意味著絕大多數(shù)情況下坐標(biāo)落在此區(qū)間但極亮的顏色或更換參考白后可能輕微越界。例如#0000ff的 C* 值約為 1.338。這一點(diǎn)在 colors.go 的 HCL 注釋中也有體現(xiàn)C 值可以超過(guò) 1.0。在需要參考白的顏色空間XYZ、Lab、Luv、HCL中庫(kù)默認(rèn)使用D65標(biāo)準(zhǔn)照明體作為參考白同時(shí)提供以自定義參考白如 D50計(jì)算的變體函數(shù)。D65 與 D50 的白點(diǎn)常數(shù)定義在 colors.go。該用哪個(gè)顏色空間感知 VS 產(chǎn)生 VS 思考原文檔引用I want hue項(xiàng)目團(tuán)隊(duì)的觀點(diǎn)給出了一個(gè)非常實(shí)用的選型準(zhǔn)則RGB對(duì)應(yīng)屏幕如何產(chǎn)生顏色——適合直接驅(qū)動(dòng)顯示器、像素寫(xiě)入等場(chǎng)景CIE-L*a*b*對(duì)應(yīng)人類如何感知顏色——適合做顏色差異比較HCLCIE-L*C*h°對(duì)應(yīng)人類如何思考顏色——適合做漸變、隨機(jī)取色這類需要看起來(lái)協(xié)調(diào)的操作。作者特別強(qiáng)調(diào)凡是打算用 HSV 的地方都建議換成 CIE-L*C*h°。因?yàn)樵诠潭鞫?L* 與色度 C* 時(shí)旋轉(zhuǎn)色相角 h° 得到的是感知亮度與強(qiáng)度完全一致的一組顏色這正是 HSV 做不到的。從 colors.go 的源碼可以印證HCL 其實(shí)就是 Lab 的柱坐標(biāo)變換——LabToHcl通過(guò)atan2(b, a)計(jì)算色相角、用sqrt(a2b2)計(jì)算色度HclToLab再用c*cos(H)與c*sin(H)還原回直角坐標(biāo)。庫(kù)作者在注釋中直言這是a correct HSV一個(gè)正確的 HSV。安裝與基礎(chǔ)用法安裝引入方式與標(biāo)準(zhǔn) Go 依賴一致$ go get github.com/lucasb-eyer/go-colorful在代碼中導(dǎo)入import github.com/lucasb-eyer/go-colorfulTilt 項(xiàng)目本身是通過(guò)go mod vendor的方式把該庫(kù)固定為 v1.0.2 并放入 vendor/github.com/lucasb-eyer/go-colorful 目錄的包內(nèi)共有 7 個(gè)源文件colors.go核心轉(zhuǎn)換與距離/混合、colorgens.go隨機(jī)單色、hexcolor.go數(shù)據(jù)庫(kù)友好類型、warm_palettegen.go與happy_palettegen.go快捷調(diào)色板、soft_palettegen.go可約束調(diào)色板。從不同顏色空間創(chuàng)建同一種藍(lán)色原文檔給出的示例用多種顏色空間描述同一個(gè)顏色#517AB8// 以下任意一種寫(xiě)法最終得到的都是同一個(gè)顏色 c : colorful.Color{0.313725, 0.478431, 0.721569} c, err : colorful.Hex(#517AB8) if err ! nil { log.Fatal(err) } c colorful.Hsv(216.0, 0.56, 0.722) c colorful.Xyz(0.189165, 0.190837, 0.480248) c colorful.Xyy(0.219895, 0.221839, 0.190837) c colorful.Lab(0.507850, 0.040585, -0.370945) c colorful.Luv(0.507849, -0.194172, -0.567924) c colorful.Hcl(276.2440, 0.373160, 0.507849) fmt.Printf(RGB values: %v, %v, %v, c.R, c.G, c.B)再把這同一個(gè)顏色轉(zhuǎn)回各種空間hex : c.Hex() h, s, v : c.Hsv() x, y, z : c.Xyz() x, y, Y : c.Xyy() l, a, b : c.Lab() l, u, v : c.Luv() h, c, l : c.Hcl()從源碼看轉(zhuǎn)換鏈路的底層實(shí)現(xiàn)是值得注意的Lab()內(nèi)部先走Xyz()Xyz()內(nèi)部先走LinearRgb()見(jiàn) colors.go。也就是說(shuō)所有 CIE 空間的轉(zhuǎn)換都經(jīng)由線性 RGB → XYZ這條鏈路這也是 FAQ 中轉(zhuǎn)換慢的根源后面會(huì)專門(mén)講性能優(yōu)化。關(guān)于命名需要說(shuō)明由于 Go 要求公開(kāi)方法必須首字母大寫(xiě)xyY 空間的方法名看起來(lái)有些錯(cuò)位Xyy、XyyWhiteRef這是原文檔作者也承認(rèn)的命名缺憾。與 Go 標(biāo)準(zhǔn)庫(kù) color.Color 的互操作colorful.Color實(shí)現(xiàn)了image/color包中的color.Color接口RGBA()方法見(jiàn) colors.go因此它可以被用在任何期望color.Color的地方例如標(biāo)準(zhǔn)庫(kù)的image/draw、image/png等繪圖管線。反向轉(zhuǎn)換則使用MakeColorc, ok : colorful.MakeColor(color.Gray16{12345})重要注意CaveatMakeColor在 alpha 恰好為 0 時(shí)會(huì)遇到邊界情況。因?yàn)閏olor.Color使用預(yù)乘 alphapre-multiplied alphaalpha 為 0 意味著 RGB 分量已被清零且無(wú)法恢復(fù)此時(shí)MakeColor會(huì)返回false作為第二個(gè)返回值。源碼邏輯見(jiàn) colors.go當(dāng)a 0時(shí)直接返回Color{0, 0, 0}, false否則把預(yù)乘的 RGB 值除以 alpha 還原再歸一化到 [0..1]。這是 v1.0 版本引入的 API 破壞性變更此前 alpha 為 0 時(shí)直接panic現(xiàn)在改為返回布爾值表示成敗。顏色距離為什么 RGB 距離不可靠原文檔的核心觀點(diǎn)RGB 空間中的歐幾里得距離與視覺(jué)/感知距離不對(duì)應(yīng)。兩組在 RGB 空間距離相同的顏色人眼看起來(lái)可能差別很大。因此應(yīng)只在 CIE-L*a*b*、CIE-L*u*v*、CIE-L*C*h° 這類感知均勻的空間中比較顏色Lab 與 HCL 的距離相等因?yàn)槎弑举|(zhì)是同一空間的不同坐標(biāo)系。原文檔附帶了一個(gè)完整可運(yùn)行的對(duì)比程序可參考其思路package main import fmt import github.com/lucasb-eyer/go-colorful func main() { c1a : colorful.Color{150.0 / 255.0, 10.0 / 255.0, 150.0 / 255.0} c1b : colorful.Color{53.0 / 255.0, 10.0 / 255.0, 150.0 / 255.0} c2a : colorful.Color{10.0 / 255.0, 150.0 / 255.0, 50.0 / 255.0} c2b : colorful.Color{99.9 / 255.0, 150.0 / 255.0, 10.0 / 255.0} fmt.Printf(DistanceRgb: c1: %v\tand c2: %v\n, c1a.DistanceRgb(c1b), c2a.DistanceRgb(c2b)) fmt.Printf(DistanceLab: c1: %v\tand c2: %v\n, c1a.DistanceLab(c1b), c2a.DistanceLab(c2b)) fmt.Printf(DistanceLuv: c1: %v\tand c2: %v\n, c1a.DistanceLuv(c1b), c2a.DistanceLuv(c2b)) fmt.Printf(DistanceCIE76: c1: %v\tand c2: %v\n, c1a.DistanceCIE76(c1b), c2a.DistanceCIE76(c2b)) fmt.Printf(DistanceCIE94: c1: %v\tand c2: %v\n, c1a.DistanceCIE94(c1b), c2a.DistanceCIE94(c2b)) fmt.Printf(DistanceCIEDE2000: c1: %v\tand c2: %v\n, c1a.DistanceCIEDE2000(c1b), c2a.DistanceCIEDE2000(c2b)) }運(yùn)行結(jié)果來(lái)自原文檔$ go run colordist.go DistanceRgb: c1: 0.3803921568627451 and c2: 0.3858713931171159 DistanceLab: c1: 0.32048458312798056 and c2: 0.24397151758565272 DistanceLuv: c1: 0.5134369614199698 and c2: 0.2568692839860636 DistanceCIE76: c1: 0.32048458312798056 and c2: 0.24397151758565272 DistanceCIE94: c1: 0.19799168128511324 and c2: 0.12207136371167401 DistanceCIEDE2000: c1: 0.17274551120971166 and c2: 0.10665210031428465解讀兩組顏色在 RGB 空間的距離幾乎相同0.380 與 0.386但在 Lab/Luv 空間中第一組的距離明顯更大——這與第一組看起來(lái)差異更大的視覺(jué)直覺(jué)一致。結(jié)論是優(yōu)先使用 CIE 系列距離。從 colors.go 的源碼可以看出三種距離的遞進(jìn)關(guān)系DistanceLab即DistanceCIE76Lab 空間的簡(jiǎn)單歐氏距離計(jì)算最廉價(jià)DistanceCIE94引入亮度、色度、色相權(quán)重因子源碼中注釋了紡織品場(chǎng)景可使用kl2.0, k10.048, k20.014精度更高DistanceCIEDE2000Delta E 2000 公式最準(zhǔn)確但最昂貴內(nèi)部還提供可自定義kl/kc/kh權(quán)重的DistanceCIEDE2000klch。另外AlmostEqualRgb僅建議用于單元測(cè)試場(chǎng)景——它在 RGB 空間用容差Delta 1/255判斷近似相等見(jiàn) colors.go 與 colors.go原文檔用了一句玩笑話強(qiáng)調(diào)使用前務(wù)必確認(rèn)你真的知道自己在做什么。顏色混合與漸變感知平滑的秘訣混合blending本質(zhì)上是在顏色空間里走一條路。如果這個(gè)空間的距離映射得好走起來(lái)就平滑反之如 HSV就會(huì)出現(xiàn)中間色帶偏的問(wèn)題。go-colorful 提供了 RGB、HSV 以及全部 Lab 系空間的混合函數(shù)BlendRgb、BlendHsv、BlendLab、BlendLuv、BlendHcl。原文檔以#fdffcc到#242a42的混合為例對(duì)比了各空間的表現(xiàn)HSV 最差中間混出了原始顏色中完全不存在綠色RGB 較好但亮得太久LUV 與 LAB明度軌跡正確LAB 的中間色更有顏色HCL 最佳同為柱坐標(biāo)插值但不會(huì)出現(xiàn)多余綠色明度線性變化。源碼印證BlendHcl與BlendHsv都通過(guò)interp_angle做色相角度的最短弧插值見(jiàn) colors.go區(qū)別在于 HCL 走的是感知均勻空間。必須警惕的坑在 CIE 空間插值時(shí)中途可能產(chǎn)生非法的 RGB 顏色——因?yàn)?Lab/Luv/HCL 的坐標(biāo)范圍遠(yuǎn)大于 sRGB 色域。原文檔給出的實(shí)例是從#eeef61到#1e3140混合時(shí)底部會(huì)出現(xiàn)偏紅但 RGB 值越界的顏色。處理方式有兩個(gè)用IsValid()判斷任一 RGB 分量超出 [0..1] 即非法實(shí)現(xiàn)見(jiàn) colors.go用Clamped()就近夾取到合法顏色逐通道 clamp 到 [0..1]實(shí)現(xiàn)見(jiàn) colors.go得到鄰近且有效的顏色。原文檔附帶了一個(gè)完整的漸變繪制程序生成五段色帶分別用 HSV/LUV/RGB/LAB/HCL 混合并演示如何用.Clamped()修復(fù)非法顏色可以照此實(shí)現(xiàn)package main import fmt import github.com/lucasb-eyer/go-colorful import image import image/draw import image/png import os func main() { blocks : 10 blockw : 40 img : image.NewRGBA(image.Rect(0, 0, blocks*blockw, 200)) c1, _ : colorful.Hex(#fdffcc) c2, _ : colorful.Hex(#242a42) // 使用這兩組顏色即可在漸變中產(chǎn)生非法 RGB //c1, _ : colorful.Hex(#EEEF61) //c2, _ : colorful.Hex(#1E3140) for i : 0; i blocks; i { draw.Draw(img, image.Rect(i*blockw, 0, (i1)*blockw, 40), image.Uniform{c1.BlendHsv(c2, float64(i)/float64(blocks-1))}, image.ZP, draw.Src) draw.Draw(img, image.Rect(i*blockw, 40, (i1)*blockw, 80), image.Uniform{c1.BlendLuv(c2, float64(i)/float64(blocks-1))}, image.ZP, draw.Src) draw.Draw(img, image.Rect(i*blockw, 80, (i1)*blockw, 120), image.Uniform{c1.BlendRgb(c2, float64(i)/float64(blocks-1))}, image.ZP, draw.Src) draw.Draw(img, image.Rect(i*blockw, 120, (i1)*blockw, 160), image.Uniform{c1.BlendLab(c2, float64(i)/float64(blocks-1))}, image.ZP, draw.Src) draw.Draw(img, image.Rect(i*blockw, 160, (i1)*blockw, 200), image.Uniform{c1.BlendHcl(c2, float64(i)/float64(blocks-1))}, image.ZP, draw.Src) // 用這行替換上面的 HCL 行即可修復(fù)漸變中的非法顏色 //draw.Draw(img, image.Rect(i*blockw,160,(i1)*blockw,200), image.Uniform{c1.BlendHcl(c2, float64(i)/float64(blocks-1)).Clamped()}, image.ZP, draw.Src) } toimg, err : os.Create(colorblend.png) if err ! nil { fmt.Printf(Error: %v, err) return } defer toimg.Close() png.Encode(toimg, img) }生成漸變是混合最常見(jiàn)的應(yīng)用場(chǎng)景之一。原文檔用 HCL 空間生成了 Spectral colorbrewer 漸變效果遠(yuǎn)超 RGB/HSV 空間的線性漸變。漸變生成不需要任何新 API復(fù)用上述BlendHcl即可。隨機(jī)顏色與隨機(jī)調(diào)色板隨機(jī)單色在 HCL 或 HSV 空間中限制取值范圍就能生成同一色相的不同色度/明度或同一明度的隨機(jī)顏色random_blue : colorful.Hcl(180.0rand.Float64()*50.0, 0.2rand.Float64()*0.8, 0.3rand.Float64()*0.7) random_dark : colorful.Hcl(rand.Float64()*360.0, rand.Float64(), rand.Float64()*0.4) random_light : colorful.Hcl(rand.Float64()*360.0, rand.Float64(), 0.6rand.Float64()*0.4)由于隨機(jī)暖色和隨機(jī)明快色是高頻需求庫(kù)提供了四個(gè)輔助函數(shù)colorful.WarmColor() // 慢HCL 空間色彩一致性好 colorful.HappyColor() // 慢HCL 空間色彩一致性好 colorful.FastWarmColor() // 快HSV 空間 colorful.FastHappyColor() // 快HSV 空間從 colorgens.go 源碼看Fast*系列直接在一組受限的 HSV 參數(shù)區(qū)間內(nèi)隨機(jī)生成如暖色S∈[0.5,0.8]、V∈[0.3,0.6]而普通WarmColor/HappyColor在受限 HCL 區(qū)間內(nèi)隨機(jī)并循環(huán)到IsValid()為真為止丟棄不可顯示的非法顏色。使用時(shí)務(wù)必先初始化隨機(jī)種子如rand.Seed(time.Now().UnixNano())Go 1.20 之前需手動(dòng)初始化。隨機(jī)調(diào)色板當(dāng)需要生成多個(gè)彼此可區(qū)分的顏色時(shí)原文檔舉的例子是多人游戲給不同玩家分配不同顏色單個(gè)隨機(jī)就不夠用了。go-colorful 提供了一組調(diào)色板生成函數(shù)核心是盡量讓調(diào)色板內(nèi)所有顏色彼此可區(qū)分pal1, err1 : colorful.WarmPalette(10) pal2 : colorful.FastWarmPalette(10) pal3, err3 : colorful.HappyPalette(10) pal4 : colorful.FastHappyPalette(10) pal5, err5 : colorful.SoftPalette(10)非Fast版本工作在 CIE 空間感知均勻Fast版本工作在 HSV速度快但感知均勻性差非 Fast 版本在請(qǐng)求顏色過(guò)多時(shí)可能失敗返回 error——從 soft_palettegen.go 的源碼看當(dāng)采樣點(diǎn)數(shù)量小于請(qǐng)求的顏色數(shù)時(shí)會(huì)返回明確錯(cuò)誤。WarmPalette的約束邏輯可以在 warm_palettegen.go 中看到它通過(guò)SoftPaletteEx限定色度 C∈[0.1,0.4]、明度 L∈[0.2,0.5]再跑迭代調(diào)色。高級(jí)SoftPaletteEx 與自定義約束SoftPaletteEx是功能最全的入口除了顏色數(shù)量還接收一個(gè)SoftPaletteSettings結(jié)構(gòu)體字段類型含義與建議CheckColorfunc(l, a, b float64) bool對(duì) Lab 空間的坐標(biāo)做約束返回true表示該顏色落在期望區(qū)域Iterationsint迭代次數(shù)建議在 [5..100]越大越慢但調(diào)色板越精確ManySamplesbool當(dāng)CheckColor拒絕了大片色域時(shí)設(shè)為true采樣密度會(huì)從 8000 提升到約 160000例如生成 10 個(gè)棕色系顏色func isbrowny(l, a, b float64) bool { h, c, L : colorful.LabToHcl(l, a, b) return 10.0 h h 50.0 0.1 c c 0.5 L 0.5 } // 上面的約束相當(dāng)嚴(yán)格所以把 ManySamples 設(shè)為 true brownies : colorful.SoftPaletteEx(10, colorful.SoftPaletteSettings{isbrowny, 50, true})源碼 soft_palettegen.go 展示了核心算法先在 Lab 空間以固定步長(zhǎng)默認(rèn) L 步長(zhǎng) 0.05、ab 步長(zhǎng) 0.1ManySamples時(shí)加密為 0.01/0.05采樣過(guò)濾掉非法 RGB 和不滿足CheckColor的點(diǎn)再對(duì)這些采樣點(diǎn)跑K-means 聚類均值落出色域時(shí)退化為 K-medoid聚類中心就是最終調(diào)色板。這個(gè)算法思路源自I want hue項(xiàng)目的公開(kāi)描述但代碼完全從零實(shí)現(xiàn)。排序顏色原文檔標(biāo)注此功能仍為T(mén)ODOSort using dist fn尚未實(shí)現(xiàn)歡迎以 Pull Request 形式貢獻(xiàn)。線性 RGB 與高性能近似為什么需要線性 RGBsRGB 編碼帶有伽馬曲線直接對(duì) sRGB 值做算術(shù)運(yùn)算如縮放、加色不符合物理亮度規(guī)律。因此庫(kù)提供了 sRGB ? 線性 RGB 的雙向轉(zhuǎn)換r, g, b : colorful.Hex(#FF0000).FastLinearRgb()精確版LinearRgb采用標(biāo)準(zhǔn)公式v 0.04045時(shí)線性段v/12.92否則((v0.055)/1.055)^2.4見(jiàn) colors.go反向LinearRgb(r,g,b)用12.92*v與1.055*v^(1/2.4)-0.055見(jiàn) colors.go。所有 CIE 空間轉(zhuǎn)換都經(jīng)由線性 RGB → XYZ 矩陣LinearRgbToXyz的 3×3 矩陣常數(shù)在 colors.go這也是性能瓶頸所在。FastLinearRgb泰勒近似的取舍原文檔明確該庫(kù)追求正確性、可讀性與模塊化從未以速度為目標(biāo)。轉(zhuǎn)換慢的主要原因是LinearRgb使用了冪運(yùn)算。為此提供了FastLinearRgb/FastLinearRgb注意函數(shù)名有區(qū)分方法FastLinearRgb()做 sRGB→線性函數(shù)FastLinearRgb(r,g,b)做線性→sRGB精度約 0.5% 以內(nèi)速度約 5 倍重大限制輸入值必須在 [0..1] 范圍內(nèi)越界時(shí)精度急劇下降。實(shí)現(xiàn)上linearize_fast使用以 0.5 為中心的 6 階泰勒近似多項(xiàng)式見(jiàn) colors.go反方向的delinearize_fast因?yàn)榉謹(jǐn)?shù)次根高度非線性被迫分段做了三套多項(xiàng)式v0.2、v0.03、其余區(qū)間見(jiàn) colors.go常數(shù)由配套的 Jupyter notebook 推導(dǎo)。在熱循環(huán)里可這樣組合使用col : // 取到顏色 l, a, b : XyzToLab(LinearRgbToXyz(col.FastLinearRgb()))原文檔同時(shí)指出更多性能可通過(guò) SIMD 指令獲得也可針對(duì)特定轉(zhuǎn)換直接近似整條轉(zhuǎn)換函數(shù)但這些超出了該庫(kù)的職責(zé)范圍如果讀者實(shí)現(xiàn)了基于FastLinearRgb的快速Distance*/Blend*歡迎提交 PR。自定義參考白點(diǎn)默認(rèn)所有 CIE 轉(zhuǎn)換使用 D65 參考白但庫(kù)也提供了以任意[3]float64白點(diǎn)計(jì)算的函數(shù)族LabWhiteRef、LuvWhiteRef、HclWhiteRef、XyzToLabWhiteRef、LabToXyzWhiteRef等c : colorful.LabWhiteRef(0.507850, 0.040585, -0.370945, colorful.D50) l, a, b : c.LabWhiteRef(colorful.D50)內(nèi)置 D65 與 D50 白點(diǎn)常量定義于 colors.go分別是{0.95047, 1.00000, 1.08883}與{0.96422, 1.00000, 0.82521}。當(dāng)需要匹配特定顯示器或印刷標(biāo)準(zhǔn)的白點(diǎn)時(shí)如某些設(shè)計(jì)稿基于 D50這組函數(shù)非常有用。用 HexColor 讀寫(xiě)數(shù)據(jù)庫(kù)需要把顏色存進(jìn)數(shù)據(jù)庫(kù)如用戶主題色、圖表配色配置時(shí)直接用字符串#rrggbb最方便。HexColor類型正是為此而生它實(shí)現(xiàn)了database/sql.Scanner與database/sql/driver.Value兩個(gè)接口源碼見(jiàn) vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go數(shù)據(jù)庫(kù)驅(qū)動(dòng)會(huì)自動(dòng)做類型轉(zhuǎn)換var hc HexColor _, err : db.QueryRow(SELECT #ff0000;).Scan(hc) // hc HexColor{R: 1, G: 0, B: 0}; err nilScan要求數(shù)據(jù)庫(kù)值必須是 string 類型否則返回明確的類型錯(cuò)誤內(nèi)部調(diào)用Hex()解析后按位轉(zhuǎn)換Value則反向調(diào)用Color.Hex()序列化回#rrggbb字符串。FAQ 排障與注意事項(xiàng)原文檔的 FAQ 集中了四個(gè)高發(fā)問(wèn)題逐一說(shuō)明Q1數(shù)值全亂套了庫(kù)是不是有 bugA極有可能是數(shù)值范圍不對(duì)。RGB 值期望在0..1之間而不是 0..255請(qǐng)先歸一化。這也是本庫(kù)最常見(jiàn)的誤用點(diǎn)。Q2Lab/Luv/HCL 看起來(lái)完全壞掉了A典型場(chǎng)景是試圖生成并顯示 RGB乃至顯示器無(wú)法表達(dá)的顏色。例如HCL(190.0, 1.0, 1.0).RGB255()會(huì)請(qǐng)求 RGB 值(-2105.254, 300.680, 286.185)——這些值顯然不存在而RGB255()只是把數(shù)值強(qiáng)轉(zhuǎn)uint8導(dǎo)致環(huán)繞wrap-around看起來(lái)就像完全壞掉的漸變。正確做法是要么改用 RGB 中真實(shí)存在的合理參數(shù)要么調(diào)用Clamp()把結(jié)果就近鉗制到合法顏色HCL(190.0, 1.0, 1.0).Clamp().RGB255()。注源碼中該方法名為Clamped()與原文檔敘述中的Clamp()指同一功能。RGB255()的實(shí)現(xiàn)見(jiàn) colors.go它就是uint8(R*2550.5)的四舍五入強(qiáng)轉(zhuǎn)不做任何邊界檢查。Q3熱循環(huán)里 Lab/Luv/HCL 轉(zhuǎn)換太慢A這是設(shè)計(jì)取向的必然結(jié)果——庫(kù)優(yōu)先保證正確、可讀、模塊化。瓶頸在于轉(zhuǎn)換鏈路經(jīng)過(guò)使用冪運(yùn)算的LinearRgb??筛挠眉s 5 倍速、精度約 0.5% 的FastLinearRgb限制是輸入必須在 [0..1] 內(nèi)組合方式見(jiàn)上文高性能近似一節(jié)。Q4為什么MakeColor會(huì)失敗A當(dāng) alpha 通道為 0 時(shí)轉(zhuǎn)換無(wú)定義預(yù)乘 alpha 已丟失 RGB 信息此時(shí)返回false。這也是 v1.0 版本相對(duì) v0.9 的 API 破壞性變更點(diǎn)。版本與許可v1.0MakeColor行為變更——alpha 為 0 時(shí)由panic改為返回(Color, bool)v0.9首個(gè)正式版本號(hào)此前長(zhǎng)期未做版本管理。Tilt 倉(cāng)庫(kù)鎖定的版本為 v1.0.2見(jiàn) go.mod。該庫(kù)以 MIT 許可發(fā)布LICENSE由 Lucas Beyer 開(kāi)發(fā)并有 Bastien Dejean、Phil Kulak、Christian Muehlhaeuser 等社區(qū)貢獻(xiàn)者參與。需要深入閱讀完整實(shí)現(xiàn)時(shí)可查看 colors.go903 行覆蓋全部顏色空間轉(zhuǎn)換、距離與混合、soft_palettegen.goK-means 調(diào)色板算法以及 hexcolor.go數(shù)據(jù)庫(kù)類型并利用庫(kù)自帶的單元測(cè)試驗(yàn)證行為。小結(jié)go-colorful 的精髓可以濃縮為三句話RGB 是給屏幕用的Lab 是給人眼用的HCL 是給人腦用的。凡是涉及顏色比較、混合、隨機(jī)取色與調(diào)色板生成的 Go 場(chǎng)景優(yōu)先考慮在感知均勻的 CIE 空間內(nèi)操作同時(shí)牢記兩個(gè)關(guān)鍵邊界——CIE 空間插值可能越出 sRGB 色域用IsValidClamped兜底以及 RGB 值必須歸一化到 [0..1]。掌握了這些無(wú)論是給玩家分配可區(qū)分的顏色、生成協(xié)調(diào)的 UI 漸變還是為數(shù)據(jù)可視化構(gòu)造感知均勻的色帶都能在 Tilt 或其他 Go 項(xiàng)目中直接復(fù)用這套經(jīng)過(guò)驗(yàn)證的能力。贊分享開(kāi)發(fā)工具云原生微服務(wù)【免費(fèi)下載鏈接】tiltDefine your dev environment as code. For microservice apps on Kubernetes.項(xiàng)目地址https://gitcode.com/gh_mirrors/tilt/tilt點(diǎn)擊查看免費(fèi)下載相關(guān)推薦go-colorful 實(shí)戰(zhàn)全解深入 Go 語(yǔ)言的顏色空間轉(zhuǎn)換與調(diào)色庫(kù)go colorful 實(shí)戰(zhàn)全解深入 Go 語(yǔ)言的顏色空間轉(zhuǎn)換與調(diào)色庫(kù) 本篇文章以 lazydocker 倉(cāng)庫(kù)中打包的第三方 Go 色彩處理庫(kù) go colo開(kāi)發(fā)工具CLIlazygit 依賴解析go-colorful 顏色空間轉(zhuǎn)換、距離度量與調(diào)色板生成實(shí)戰(zhàn)指南lazygit 依賴解析go colorful 顏色空間轉(zhuǎn)換、距離度量與調(diào)色板生成實(shí)戰(zhàn)指南 本文以 lazygit 倉(cāng)庫(kù)中 vendored 的第三方庫(kù) go開(kāi)發(fā)工具CLI版本控制Sliver 倉(cāng)庫(kù)中的 go-colorful 色彩引擎從顏色空間轉(zhuǎn)換到感知均勻色板生成的完整實(shí)踐Sliver 倉(cāng)庫(kù)中的 go colorful 色彩引擎從顏色空間轉(zhuǎn)換到感知均勻色板生成的完整實(shí)踐 在 Sliver 對(duì)抗性模擬框架中客戶端終端 UI 需要網(wǎng)絡(luò)安全創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考