news 2026/8/22 14:43:11

像素级渲染生成色彩图:Colorful ColorMapView颜色轮实现原理深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
像素级渲染生成色彩图:Colorful ColorMapView颜色轮实现原理深度解析

像素级渲染生成色彩图:Colorful ColorMapView颜色轮实现原理深度解析

【免费下载链接】Color-Picker-for-iOSColorful: iOS color picker built with Swift.项目地址: https://gitcode.com/gh_mirrors/co/Color-Picker-for-iOS

Colorful 是一款用 Swift 编写的 iOS 取色器(Color Picker)库,其中的颜色轮由ColorMapView通过像素级渲染逐点绘制生成,支持 sRGB 与扩展 sRGB(Display P3)宽色域。本文将带你深入解析这个圆形 HSB 颜色轮从数学模型到像素渲染的完整实现原理,即使你是 iOS 新手也能轻松看懂。

一、Colorful 是什么?一个高颜值的 iOS 取色器

Colorful 的取色器由四部分组合而成:

  • 🎨颜色轮(ColorMapView):圆形区域,横轴为色相(Hue)、半径为饱和度(Saturation)
  • 📏亮度滑杆(BrightnessSlider):右侧竖条,上下滑动调节明度(Brightness)
  • 🎯颜色轮光标(ColorMapCursor):跟随手指移动的圆点指示器
  • ⚙️容器(ColorPicker):继承自UCtrl(UIControl),负责手势分发与事件回调

整个 UI 的组装逻辑在 ColorPicker.swift 中,各子视图分别位于Colorful/Classes/目录下。

二、核心原理 1:圆形颜色轮的数学模型

颜色轮的本质是一次坐标系变换:把手指在圆盘上的位置(直角坐标)转换为 HSB 颜色(色相 + 饱和度)。这部分由ColorMapView.swift底部的HRColorMapModel类完成。

位置 → 颜色的映射规则非常直观:

  1. 饱和度 = 距圆心距离 × 2(距离超过半径 0.5 时封顶为 1,因此圆心是纯色中心)
  2. 色相 = 指针与圆心连线的角度(顺时针 0~360°,对应 HSB 的 0~1 归一化色相)

用三角函数实现起来只有几行:hypot()求半径、atan2()求角度,再归一化到 0~2π 区间即可。

颜色 → 位置则是它的逆运算(用于程序化设置取色器初始颜色时定位光标):

  • 半径 = 饱和度 ÷ 2
  • 角度 = 色相 × (−2π)
  • cos/sin还原出圆盘上的坐标,最后加上圆心偏移 (0.5, 0.5)

这套正逆映射保证了「手指点哪里,就取到什么颜色;设置什么颜色,光标就停在哪里」,二者严格一致。

三、核心原理 2:像素级渲染,逐点"画"出颜色图

颜色轮图片不是截图、不是渐变图层,而是实时逐像素计算生成的。关键方法是createColorMapImage(size:model:)(位于 ColorMapView.swift 第 31~67 行):

  1. 分配原始内存:为宽 × 高 × 3字节的 RGB 数据申请一块CFMutableData缓冲区
  2. 双重循环遍历每个像素:对每个 (x, y) 坐标,先归一化为 0~1 的圆盘坐标,再调用上一步的HRColorMapModel.color(at:)算出该点对应的 HS 颜色
  3. 换算为 RGB:以亮度 1(最亮)为基准把 HS 颜色转换为 8bit 的 R/G/B 字节,按行优先顺序写入缓冲区
  4. 封装成 CGImage:用CGDataProvider包装原始数据,指定色彩空间后创建CGImage,并设置shouldInterpolate: false禁止插值——这是保证颜色轮边缘色相过渡精准的关键细节

最终这张 CGImage 被赋值给CALayercontents属性显示在屏幕上,并用CAShapeLayer的圆形路径作为mask,把正方形渲染结果"裁"成圆盘形状。

💡 为什么选择逐像素渲染?因为 HSB 颜色轮是非线性渐变,任何简单的渐变图层或 Core Graphics 路径着色都无法精确还原"角度=色相、半径=饱和度"的数学关系,只有逐点计算才能保证所见即所得。

四、宽色域支持:sRGB 与扩展 sRGB

Colorful 的一大亮点是同时支持两种色彩空间,由HRColorSpace枚举定义(见 ColorfulEntity.swift):

色彩空间底层实现适用场景
.sRGBCGColorSpace.sRGB标准色彩,兼容性最好
.extendedSRGBCGColorSpace.displayP3覆盖更广的 P3 色域,颜色更鲜艳

渲染时会为CGImage选择对应的色彩空间;颜色与 UIKit 的互转则集中在HSVColor的扩展中完成——uiColor属性会根据当前色彩空间自动选择UIColor(hue:...)还是UIColor(displayP3Red:...)构造器,确保 P3 颜色不会被错误压缩到 sRGB。

五、亮度如何影响颜色轮?一个巧妙的"透明度"技巧

很多人会疑惑:颜色轮上明明只渲染了亮度=1 的最亮颜色,那亮度是怎么生效的?

答案藏在ColorMapViewset(brightness:)方法里:

  • 颜色轮图片始终保持最亮状态
  • 调节亮度时,直接把整个colorMap图层的opacity设为亮度值
  • 图层下方垫了一个黑色背景层,因此透明度越高(亮度越低),颜色就越黑

这个"黑色背景 + 透明度"的技巧避免了亮度变化时重新逐像素渲染整张图,性能开销几乎为零。而右侧亮度滑杆(BrightnessSlider.swift)则用 20 个小色块实时展示当前 HS 颜色在不同亮度下的梯度,方便用户预览。

六、触摸交互:从手指坐标到颜色的完整链路

当你在颜色轮上滑动时,ColorPickerhandleColorMapPan(pan:)会启动如下链路:

  1. 手指坐标通过normalize()换算为 0~1 的归一化圆盘坐标
  2. HRColorMapModel.color(at:)算出新的色相与饱和度
  3. 合并当前亮度得到完整HSVColor
  4. mapColorToView()同步刷新:光标位置、亮度滑杆色块、以及颜色轮透明度
  5. 触发valueChanged事件,并伴随触觉反馈UISelectionFeedbackGenerator

其中光标的位置又用到「颜色 → 位置」的逆映射,形成完整的闭环。

七、总结

Colorful 的ColorMapView颜色轮实现堪称小型教学范本,核心可以归纳为三点:

  • 📐数学模型先行:用极坐标(角度=色相,半径=饱和度)定义颜色轮,正逆映射保证双向精确
  • 🖌️像素级渲染:逐点计算 RGB 写入内存缓冲区,生成无插值的CGImage,圆形 mask 裁出圆盘
  • 性能小聪明:亮度变化只改图层透明度,宽色域切换交给色彩空间枚举统一管理

如果你想在自己的 iOS 项目中加入一个美观、支持宽色域、带触觉反馈的取色器,Colorful 是一个非常值得参考的轻量级选择——它的核心源码不足 500 行,阅读Colorful/Classes/下的六个文件即可掌握全部实现细节。

【免费下载链接】Color-Picker-for-iOSColorful: iOS color picker built with Swift.项目地址: https://gitcode.com/gh_mirrors/co/Color-Picker-for-iOS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!