亮度、饱和度与色相调整
这三个操作都改变像素外观,但不是同一件事:亮度改变明暗,饱和度改变色彩强度,色相改变色轮上的位置。下面每节只讨论一个变体,图片和代码来自同一个 Recipe。

参考输出由 govips v2.19.0 / libvips 8.17.3 生成。四个 binding 都有对应输出;pyvips 与 CLI 的饱和度、色相文件目前是原图占位,状态为 not-supported,不应当当作调整结果。
govips.Modulate(1.25, 1, 0) 在 LCh 中提高亮度;sharp 使用 HSL 语义。pyvips 与 CLI 示例使用 RGB 线性乘法,是近似而非像素等价实现。


Generated with govips v2.19.0 / libvips 8.17.3.
image, err := vips.NewImageFromFile("input.jpg")if err != nil { return err }defer image.Close()if err := image.Modulate(1.25, 1, 0); err != nil { return err }data, _, err := image.ExportWebp(vips.NewWebpExportParams())if err != nil { return err }return os.WriteFile("brightness.webp", data, 0o644)await sharp('input.jpg').modulate({ brightness: 1.25 }).webp({ quality: 82 }).toFile('brightness.webp');image = pyvips.Image.new_from_file("input.jpg")bright = image.linear([1.25, 1.25, 1.25], [0, 0, 0])bright.write_to_file("brightness.webp", Q=82)vips linear input.jpg 'brightness.webp[Q=82]' 1.25 0govips 和 sharp 有直接的调制入口。当前 pyvips 与 CLI 会保留输入并在结果清单中标记 not-supported;这表示流程可运行,但没有声称已经完成饱和度变换。


Generated with govips v2.19.0 / libvips 8.17.3.
if err := image.Modulate(1, 0.35, 0); err != nil { return err }await sharp('input.jpg').modulate({ saturation: 0.35 }).webp({ quality: 82 }).toFile('saturation.webp');# 当前 Recipe 明确标记为 not-supported;不要把原图当成调整结果。image.write_to_file("saturation.webp", Q=82)# 当前 Recipe 明确标记为 not-supported。vips copy input.jpg 'saturation.webp[Q=82]'色相是角度偏移,60 表示旋转 60 度。govips 的 Modulate 在 LCh 中处理;sharp 的实现使用 HSL,因此相同数字不保证得到相同像素。


Generated with govips v2.19.0 / libvips 8.17.3.
if err := image.Modulate(1, 1, 60); err != nil { return err }await sharp('input.jpg').modulate({ hue: 60 }).webp({ quality: 82 }).toFile('hue.webp');# 需要手动完成 LCh round-trip;当前 Runner 尚未实现该变换。image.write_to_file("hue.webp", Q=82)# 需要 colourspace LCh → 调整 hue 通道 → colourspace sRGB;当前 Runner 尚未实现。vips copy input.jpg 'hue.webp[Q=82]'