Compositor:一个 20 秒写完的 macOS 图像编辑器,两天冲到 2400 星

Compositor:一个 20 秒写完的 macOS 图像编辑器,两天冲到 2400 星

Photoshop 太贵,GIMP 又太陌生——搓不出手感,就进不了心流。作者 robbietilton 干脆自己写了一个:完全免费、完全开源的 macOS 原生图像编辑器 Compositor,把日常合成与后期那套工作流原样搬过来,用 MIT 协议交给你。

项目 2026 年 9 月 16 日建仓,两天后就被 GitHub 趋势榜推了上去,截稿时 2461 星 / 262 fork。README 里那句话很直白:

因为它是开源的,你可以把 Xcode 工程拉下来,按自己的习惯加功能、删功能、改功能。

它不是「又一个 GIMP 缩水版」

Compositor 的定位非常明确:围绕「合成 + 后期」这一个场景把功能做全,而不是追求修图软件的全能。所以它给出的是一套完整可用的图层模型,而不是几个滤镜的拼盘。

图层系统

图层与图层文件夹、混合模式、不透明度是基础;真正见功夫的是蒙版那一套:

  • 图层蒙版支持画笔涂抹、填充、反相、模糊、羽化;蒙版可以链接到图层一起变换,也可以解除链接单独自由变换
  • 剪贴蒙版文件夹蒙版齐备
  • 调整图层:色相/饱和度、色阶、曲线、曝光、渐变映射、颗粒
  • 合并方式区分「向下合并 / 合并图层 / 合并组」(⌘E)
  • 图层支持拖拽重排、嵌套、内联重命名,Option 拖拽直接复制,甚至能跨打开的工程拖图层

变换

全部是非破坏性的:移动、缩放、旋转、翻转之后,图像本身保留完整分辨率——你把它缩得再小,像素也没丢。

  • 自由变形(⌘ 拖手柄),按住 Shift 锁定单轴
  • 可以同时变换多个图层或整个文件夹
  • 吸附到画布与图层边缘、中心,带参考线
  • 位置、尺寸、缩放、角度有精确数值输入,方向键微调

选区

矩形/椭圆选框、自由套索、多边形套索、魔棒;支持加选减选、移动轮廓、移动或复制轮廓内的像素;可以把图层像素或蒙版载入为选区。

这里有一个挺硬的功能:内容识别填充,而且它能把图像扩展到画布边缘之外——不是简单地在画布里补洞,是真往外长。

绘画与修饰

  • 画笔:大小、硬度、不透明度可调,Shift 点两点画直线
  • 污点修复画笔(内容识别)
  • 仿制图章:可对齐/不对齐,可从单图层或所有图层取样
  • 模糊工具:既能作用在像素上,也能直接涂蒙版
  • 渐变工具、形状工具(矩形、圆角矩形、椭圆)
  • 吸管与完整取色器

调整与滤镜

色阶(带自动)、曲线、色相/饱和度、曝光、渐变映射、颗粒、反相;高斯模糊与运动模糊可以溢出图层边界;加噪、镜头校正、移除背景。所有调整都支持实时预览,而且有选区时预览只作用于选区

与其他工具的差异

工程用多标签页管理;裁剪带吸附,按住 Option对称裁剪;缩小视图时用锐利高质量重采样,放大时给像素网格;导入支持 JPEG / PNG / HEIC / TIFF,包括从其他 App 直接拖进来的截图和图片;导出 JPEG 带实时预览(⇧⌥⌘S),另有「复制合并」。快捷键整体沿用 Photoshop 习惯——这也是作者敢说自己「熟悉」的底气:迁移成本接近零

真正的技术看点:那个 4K 画笔

如果只把 Compositor 当成「界面像 PS」,那就低估它了。仓库里 docs/brush-performance.md 那份性能文档,是全项目最值得读的部分。

从「盖章」到「积分」

最初的连续画笔实现是在每个像素取最大衰减值。这确实消掉了盖章式的棱纹感,但两条羽化边缘交会的地方会出现一道锐利的折痕

现在改成:软头画笔沿平滑后的指针路径积分「光学密度」,再把累积密度换算成覆盖率——数学上等价于按直径 2.5% 间距做 source-over 盖章,但结果与指针事件数量完全无关。永久笔迹存在浮点 tile 缓冲里,临时笔尾单独放另一个缓冲,替换笔尾永远不会把旧像素留在原地。

硬头画笔保留抗锯齿轮廓;软件回退路径用 2.5%(软)/ 1.5%(硬)间距。

提交笔迹不等于卡住

鼠标抬起时,会一次性安装一个不可变的 RasterSnapshot,并同步记入撤销条目。快照之间共享未变动的 tile,用空间索引把替换列表压扁。边界查找不再用未优化的 Swift 扫描整张文档,而是一个小的优化过的 C 例程在「已变动的 tile」里找。

画布和后续笔迹直接读 tile;只有在导出或图像处理操作需要字节时,才惰性生成连续的 CGImage。蒙版走同一套快照交接流程,包括新扩展区域里的白色覆盖率。

Metal 管线由系统编译器编译一次,并在选中画笔时预热——这点很重要,它不需要 Xcode 的可选 Metal 工具链

实测数据(2026-09-12)

4000 × 4000 文档、800 px 画笔、硬度 0%、不透明度 100%。两笔画,每笔 120 次指针更新、每次移动 40 个文档像素,在 1000 × 1000 的原生 NSWindow 里按适应缩放作画。计时包含模型更新与 CanvasView.synchronizeDisplay() / displayIfNeeded();鼠标抬起包含 flush、commit、history 和紧随其后的显示。作者明确标注:这是同步的 CPU 计时,不是输入到光子的延迟,也不是跟 Photoshop 的对比测试。

Debug,空白绘画图层 优化前 优化后
指针更新中位数 6.54 ms 2.64 ms
指针更新 P95 11.98 ms 3.70 ms
鼠标抬起,第一笔 1058 ms 8.71 ms
鼠标抬起,第二笔 1002 ms 8.14 ms

在已有不透明内容的 4K 图层上,800 px 画笔的数据是 2.80 ms 中位 / 5.38 ms P95,鼠标抬起 5.2–6.2 ms;40 px 画笔则是 0.36–0.47 ms 中位,抬起 1.3–4.8 ms。

Release 配置也跑了同一套基准:800 px 空白图层中位 2.81 ms,抬起 9.6–11.0 ms(优化前是 87–111 ms)。作者还特意提示不同硬件、视口、图层栈和系统负载会影响结果,不承诺任何固定的帧率

加上自交修正之后,800 px / 4K 的 Debug 基准落在 3.08–3.12 ms 中位更新、6.3–9.7 ms 抬起。

基准可复现

性能测试可以单独跑,避免其他主线程测试争抢:

TEST_RUNNER_BRUSH_BENCHMARK=1 xcodebuild \
  -project Compositor.xcodeproj -scheme Compositor -configuration Debug \
  -derivedDataPath /tmp/CompositorBrush -destination 'platform=macOS' \
  CODE_SIGNING_ALLOWED=NO ENABLE_DEBUG_DYLIB=NO \
  -parallel-testing-enabled NO \
  -only-testing:CompositorTests/BrushPerformanceTests test

基准会打 BRUSH BENCH 日志,并导出 /tmp/compositor-brush-benchmark.png 供肉眼检查,同时覆盖空白图层与不透明图层两种场景。

测试规模上,自交修正后的完整 Debug 套件是 175 个测试 / 26 个套件通过。

工程细节里藏着的态度

自己发明了一套工程文件格式

.comp 是 macOS 的 document package,内含 manifest.json 和一个 images/ 目录(<图层 UUID>.png)。清单声明 com.compositor.project,新保存写版本 6,1–5 版本仍然可读,工作色彩空间是 sRGB。

关键设计:嵌入的 PNG 保留原始像素与透明度,变换是分离存储的。也就是说,你搬走甚至删掉当初导入的源照片,工程照样能开。保存走的是协调后的原子化 package 替换

版本演进写得很克制,每个版本都只做加法:

  • v2parentID / isGroup,数组顺序定义兄弟图层从下到上的次序,渲染器把每个组当连续子树遍历;可见性继承但不改动子图层标志位。检测到环、缺失或非组父级、带图像的组、超过 64 层嵌套一律拒绝
  • v3 加图层级 opacityblendMode(正常、正片叠底、滤色、叠加、变暗、变亮、差值、颜色减淡、颜色加深),缺省即满不透明 + 正常
  • v4maskFile / maskEnabled,蒙版是 <图层 UUID>.mask.png,8 位灰度无 alpha,白色显示黑色隐藏;1×1 的均匀蒙版是合法值,避免作画前先分配全分辨率像素
  • v5maskSourceID——用另一个图层的实时 alpha 在文档坐标系里做乘算,也就是 UI 上说的剪贴蒙版;源像素、变换、不透明度、栅格蒙版与上游实时蒙版都参与覆盖计算,而可见性和 RGB 颜色不参与
  • v6 允许组也带蒙版,组是穿透的,启用的文件夹蒙版会与每个后代图层自身的蒙版、以及所有外层文件夹蒙版相乘

限制是有明确数字的:画布/图像单边 30000 像素、源像素总量 1 亿、图层数 10000、manifest 4 MiB、单个编码资源 512 MiB;蒙版另计 1 亿像素。不支持的版本、非法元数据、缺失资源、不安全路径、超限数据,都会在替换掉当前文档之前被拒

不写空头承诺

撤销历史和视口是会话级的,不做序列化;PNG 导出只是压平后的衍生物,不代表工程已经保存——这种话说清楚,比藏起来强。

发布流程也没藏着:scripts/release.sh 会构建 Release、用 Developer ID 签名、公证并 stapler、最后打包成 dist/Compositor-.dmg。证书、公证凭据、create-dmg 全都要求放在仓库外面。

怎么上手

要求 macOS 26,从源码构建需要 Xcode 26

git clone https://github.com/robbietilton/Compositor.git
cd Compositor
open Compositor.xcodeproj

然后运行 Compositor scheme 就行。

值不值得看

它的价值不在「功能比 Photoshop 多」——那不可能。它的价值在于三件事:

1. 完整的图层/蒙版模型,而不是「能修图」的玩具,日常做合成和后期真的能顶

2. 一份把性能拆到毫秒、把格式拆到字段的性能与格式文档,这是很多开源项目最缺的东西

3. MIT + 完整 Xcode 工程,意味着它能变成你的编辑器——这也是作者写它的理由

顺手记一下:迁移成本几乎为零(快捷键是 PS 那套),工程文件格式自己造但向后兼容,画笔提交从 1 秒降到 8 毫秒。

感兴趣的可以直接去看 项目仓库,或者先读 画笔性能文档工程格式文档

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容