从一个 .xmp 文件 到你留下的那一张。

预设只被解析一次,变成一组参数;为取景框烘焙成一张三维查找表;按下快门时,再以完整的浮点精度在未压缩的传感器画幅上重新跑一遍。两条路径由同一份用 Rust 写成的实现驱动——预览与成片一致,原因就在这里。

最后更新:

一张照片经过的路

  1. 解析文件

    .xmp 预设本质上是 XML。其中每一项 Camera Raw 属性都会被读进同一组参数:白平衡与曝光、色调与曲线、HSL、颜色分级、细节、效果,以及可能存在的蒙版。引擎不认识的属性会被忽略而不是当成错误,因此由更新版本的 Lightroom 导出的预设仍能带着它能理解的一切正常载入。

  2. 预设变成一条流水线

    这些参数会变成一串顺序固定的运算:先白平衡与曝光,再色调与曲线,再颜色,最后是与空间有关的部分——清晰度、去朦胧、锐化、蒙版、暗角与颗粒。顺序是固定的,因为同样的调整换个次序,得到的并不是同一张照片。

  3. 取景框拿到的是一张查找表

    凡是只取决于像素自身颜色的部分——曲线、HSL、颜色分级、点颜色——都会在你切换预设的那一刻一次性烘焙成三维查找表。此后 GPU 只需把这张表套到每一帧上,几乎没有额外开销,这正是风格能跟上实时画面的原因。

  4. 快门跑的是真家伙

    按下快门,同一条流水线会以浮点精度在整幅未压缩的传感器画面上重新跑一遍,其中不含查找表的任何插值。光晕与颗粒在两条路径上使用完全相同的代码,所以你在取景框里看到的质感就是你最终得到的质感。

  5. 原始画面会保留

    默认会在成片旁保存一份未经处理的副本;在 RAW 模式下,未加工的传感器数据还会单独写成一个 ProRAW 的 DNG。套用风格这件事,删掉一个文件就能撤销,不会不问一声就烙进照片里。

预览与成片为什么一致

大多数带实时滤镜的相机,预览用一套代码,出片用另一套,两者会逐渐分道扬镳——「先拍平、回头再调」这句老生常谈就是这么来的。

在这里,两条路径用同样的参数调用同一份 Rust 实现。预览让出的只有精度,换回速度:用在网格上采样的查找表代替逐像素运算,仅此而已。哪一步运算、按什么顺序、用什么数值,两边完全一致。

查找表装不下的东西

查找表把一个颜色映射到另一个颜色,因此只能承载仅取决于单个像素的调整。凡是必须看邻近像素的都属于空间处理——清晰度、去朦胧、锐化、降噪、暗角、蒙版与颗粒——它们在两条路径上都各自单独跑一遍。

这也是带好几个蒙版的预设在取景框里比不带蒙版的更吃性能的原因:每个蒙版都意味着每帧若干次全画面 GPU 运算,而它的颜色部分早已免费折进了那张表里。

对着 Lightroom 拟合,而不是猜

HSL 的饱和度与明亮度算子是对着 Lightroom 自身的输出拟合出来的,而不是凭对公式的猜测重新实现——在 Lightroom 里做好的预设,会落在作者放它的位置上。

确实没有实现的控制项,引擎会按中性值渲染并且可以如实说明,而不是拿个大致相似的东西顶上。预设是有人特意选定的一组数值;悄悄渲染成另一组,比什么都不渲染更糟。

没有任何东西离开设备

这里没有服务器。解析、渲染、拍摄与导出全部在手机上完成,照片直接写进你的图库。

如果你登录 Google Drive 或 OneDrive 来取预设,令牌会保存在 iOS 钥匙串中,且只用于读取 .xmp 文件。