简介
本手册将以 libvips 的封装 govips 为主进行介绍,中间会穿插 pyvips 和 sharp 的部分示例代码用于参考。
目录
使用方式
基本图像概念
基本概念
- 像素和分辨率
- 色彩模型:RGB、CMYK
- Alpha 通道和透明度
- 图像格式和特点(JPEG, PNG, TIFF 等)
使用方式
安装
-
在不同操作系统上安装
libvips - 安装 Python、Go、Node.js 封装包
基本操作
- 读取和导出图片
- 基本的图片格式转换
基本图像操作
- 缩放
- 裁剪
- 旋转
- 翻转和镜像
- 添加和删除 Alpha 通道
图像色彩调整
- 色彩空间转换
- 调整亮度、饱和度,色相
4. 基本图像操作
- 添加和移除 Alpha 通道
- 图像组合和图层操作
- 图像滤波:平滑、锐化
- 边缘检测和图像分割
- 在 Python、Go、Node.js 中的实现对比
第二部分:进阶篇
1. 高级图像处理
- 高级滤镜和效果
- 颜色调整:色温、色调映射
- 图像恢复和噪声消除
- 动态图像处理(如 GIF)
2. 性能优化和内存管理
- 使用延迟加载和管道处理
- 内存使用策略和优化
- 处理大型图像的策略
3. 错误处理和调试
- libvips 错误处理机制
- 性能分析和调优
- 在 Python、Go、Node.js 中的错误处理和调试技巧
4. 特殊场景处理
- 处理不常见的图像格式
- 批量处理和自动化
- 与其他图像处理库的结合使用(如 OpenCV)
第三部分:附加资源
1. 学习资源和社区
- 官方文档链接
- 相关论坛和社区
2. 常见问题解答
- 安装和配置常见问题
- 功能实现和性能优化常见问题
3. 更新记录
- 教程版本更新
- libvips 版本更新及影响
基本概念
Alpha 通道和透明度
Alpha 通道(Alpha Channel)是指图像中每个像素的额外通道,用于表示像素的透明度。它是一种图像通道,与红色(R)、绿色(G)和蓝色(B)通道一起构成了图像的颜色信息。Alpha 通道的取值范围通常是从 0 到 1,表示像素的透明度程度,其中 0 表示完全透明(像素不可见),1 表示完全不透明(像素完全可见)。
透明度(Opacity)是指物体或图像的可见程度或不透明程度。在图像处理中,透明度通常通过 Alpha 通道来表示。透明度的值可以是介于 0 和 1 之间的任意小数,其中 0 表示完全透明,物体或图像不可见,1 表示完全不透明,物体或图像完全可见。透明度的中间值表示部分透明,即物体或图像可见但部分透明。
通过使用 Alpha 通道和透明度,可以实现图像的透明效果。通过调整像素的透明度值,可以使图像中的某些区域变得透明,从而使底层的背景或其他图像可见。透明度的应用广泛,例如在图像编辑软件中,可以通过调整透明度来创建淡入淡出的效果、合成多个图像或将图像放置在不同的背景上。
安装
libvips 在不同的平台上有不同的安装方式,它可以在 Linux、macOS 和 Windows 上运行。
对于 Ubuntu 而言,安装 libvips 的方式是:
apt-get install libvips
macOS 是:
brew install vips
libvips 在不同的语言上有不同的实现(封装),在安装了 libvips 之后,我们可以根据自己需要的编程语言来安装对应的库:
Go
go get -u github.com/davidbyttow/govips/v2/vips
Python
pip3 install pyvips
Node
npm install sharp
基本操作
读取和导出图片
我们以 Go 为例,在安装了 govips 之后,可以使用以下代码进行基本图像操作:
package main
import (
"github.com/davidbyttow/govips/v2/vips"
"os"
)
func main() {
vips.Startup(nil)
defer vips.Shutdown()
img, err := vips.NewImageFromFile("input.jpg")
if err != nil {
panic(err)
}
imageBytes, _, _ := img.ExportPng(vips.NewPngExportParams())
_ = os.WriteFile("output.jpg", imageBytes, 0644)
}
Python 代码案例,点这里
import pyvips
image = pyvips.Image.new_from_file('some-image.jpg', access='sequential')
image *= [1, 2, 1]
mask = pyvips.Image.new_from_list([[-1, -1, -1],
[-1, 16, -1],
[-1, -1, -1]
], scale=8)
image = image.conv(mask, precision='integer')
image.write_to_file('x.jpg')
Javascript 代码案例,点这里
const sharp = require('sharp');
sharp('input.jpg')
.rotate()
.resize(200)
.jpeg({ mozjpeg: true })
.toBuffer()
.then( data => { ... })
.catch( err => { ... });
这里 img 会是一个 ImageRef 对象,后续的所有操作都是围绕这个对象来的,所以后文中所有的操作都假设你已经有了一个 ImageRef 对象,名字为 img。
// ImageRef contains a libvips image and manages its lifecycle.
type ImageRef struct {
// NOTE: We keep a reference to this so that the input buffer is
// never garbage collected during processing. Some image loaders use random
// access transcoding and therefore need the original buffer to be in memory.
buf []byte
image *C.VipsImage
format ImageType
originalFormat ImageType
lock sync.Mutex
preMultiplication *PreMultiplicationState
optimizedIccProfile string
}
转换图片格式
例如,如果我们希望将图片从 jpg 格式转换成 webp 格式,和我们的 WebP Server Go 项目一样,我们可以使用以下代码:
package main
import (
"os"
"github.com/davidbyttow/govips/v2/vips"
)
func main() {
vips.Startup(nil)
defer vips.Shutdown()
img, err := vips.NewImageFromFile("input.jpg")
if err != nil {
panic(err)
}
imageBytes, _, _ := img.ExportWebp(vips.NewWebpExportParams())
os.WriteFile("output.webp", imageBytes, 0644)
}
其中 vips.NewWebpExportParams() 会生成一个默认的 webp 导出参数,你可以根据需要进行调整,可调参数如下:
// WebpExportParams are options when exporting a WEBP to file or buffer
type WebpExportParams struct {
StripMetadata bool
Quality int
Lossless bool
NearLossless bool
ReductionEffort int
IccProfile string
}
StripMetadata是否去除元数据Quality图片质量,范围 0-100Lossless是否无损压缩,注意上面 Quality 100 并不代表无损压缩NearLossless是否近无损压缩ReductionEffort压缩力度,范围 0-6,用NewWebpExportParams的话这个值默认是 4,这里我们踩过一些坑,比如对于某些图片来说 Effort 设置为 0 会转换失败,相关的 Issue 可以见 https://github.com/libvips/libvips/issues/3568 。 (注意这里的压缩力度并不是一个线性的关系,不同的数值对应的libvips上是不同的压缩算法,但是数值越高,转换速度越慢)
Fun fact, 对于 AVIF 格式的导出可以使用
AvifExportParams,内部也有StripMetadata选项来决定是否清除图片的源信息,但是这个功能直到govipsv2.14.0 版本发布之前都是假的,修复的 PR 是 Fix AvifExportParams StripMetadata #383
基本图像操作
本文假设你已经阅读了 基本操作,已经学会如何将一个图片读取为 ImageRef 对象和通过类似 img.ExportWebp + os.WriteFile 导出了。
这里包括了:
- 缩放、裁剪、旋转
- 翻转和镜像
- 色彩调整:亮度、对比度、饱和度
缩放
func (r *ImageRef) Thumbnail(width, height int, crop Interesting) error
如果希望改变图片的尺寸,例如将一个 2000x1000px 的图片缩小成 200x100px,可以使用 Thumbnail 方法:
img.Thumbnail(200, 100, vips.InterestingAll)
注意这里如果设置的新的尺寸和原来的的长宽比例不一致,那么图片会被裁剪成新的尺寸,裁剪的方式可以通过 vips.Interesting 参数进行设置,可选项如下:
// Interesting constants represent areas of interest which smart cropping will crop based on.
const (
InterestingNone Interesting = C.VIPS_INTERESTING_NONE
InterestingCentre Interesting = C.VIPS_INTERESTING_CENTRE
InterestingEntropy Interesting = C.VIPS_INTERESTING_ENTROPY
InterestingAttention Interesting = C.VIPS_INTERESTING_ATTENTION
InterestingLow Interesting = C.VIPS_INTERESTING_LOW
InterestingHigh Interesting = C.VIPS_INTERESTING_HIGH
InterestingAll Interesting = C.VIPS_INTERESTING_ALL
InterestingLast Interesting = C.VIPS_INTERESTING_LAST
)
我们针对不同的裁剪格式有一个完整的对比文章,敬请参考: libvips 中不同的 VipsInteresting 是怎么决定图片裁剪位置的 - WebP Cloud Services Blog
裁剪
func (r *ImageRef) Crop(left int, top int, width int, height int) error
例如,将图片从 200x100px 的位置裁剪出一个 500x500px 的小图出来:
img.Crop(200, 100, 500, 500)
| 原图 | 裁剪后 |
|---|---|
![]() | ![]() |
旋转
func (r *ImageRef) Rotate(angle Angle) error
旋转分为多种不同的旋转,一种是 90 度的整数倍旋转,另一种是任意角度的旋转,前者非常简单,只需要使用:
img.Rotate(angle)
即可,其中 angle 可选项如下:
// Angle enum
const (
Angle0 Angle = C.VIPS_ANGLE_D0
Angle90 Angle = C.VIPS_ANGLE_D90
Angle180 Angle = C.VIPS_ANGLE_D180
Angle270 Angle = C.VIPS_ANGLE_D270
)
而对于任意角度的旋转,可以使用 Similarity 函数:
func (r *ImageRef) Similarity(scale float64, angle float64, backgroundColor *ColorRGBA,
idx float64, idy float64, odx float64, ody float64) error
例子如下:
img.Similarity(1.0, float64(angleDegree), &vips.ColorRGBA{
R: 255,
G: 255,
B: 255,
A: 255,
}, 0, 0, 0, 0)
其中 1.0 是缩放比例,angleDegree 是旋转角度,ColorRGBA 是背景颜色,上面的例子中我们用 255, 255, 255, 255 表示无透明度的白色,最后四个参数是填充的位置,这里我们用 0 表示填充到图片的四周,例如给下图旋转 30 度的效果:
| 原图 | 旋转后 |
|---|---|
![]() | ![]() |
注意本文背景色是白色,和旋转后图片四周的填充色一致,所以看不出来填充的效果,实际上图片是被填充了的。
翻转和镜像
func (r *ImageRef) Flip(direction Direction) error
例如:
img.Flip(vips.DirectionHorizontal)
其中方向有两个可选:
const (
DirectionHorizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
DirectionVertical Direction = C.VIPS_DIRECTION_VERTICAL
)
如果需要上下和左右都反转,需要分别调用两次 Flip 方法并传入不同的 Direction。
| 原图 | DirectionHorizontal |
|---|---|
![]() | ![]() |
| DirectionVertical | DirectionVertical + DirectionHorizontal |
|---|---|
![]() | ![]() |
图像色彩调整
色彩空间转换
色彩空间的介绍可以在 基本概念 中看到。
func (r *ImageRef) ToColorSpace(interpretation Interpretation) error
其中 Interpretation 的可选项有如下:
// Interpretation enum
const (
InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
InterpretationHistogram Interpretation = C.VIPS_INTERPRETATION_HISTOGRAM
InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
InterpretationLABQ Interpretation = C.VIPS_INTERPRETATION_LABQ
InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
InterpretationCMC Interpretation = C.VIPS_INTERPRETATION_CMC
InterpretationLCH Interpretation = C.VIPS_INTERPRETATION_LCH
InterpretationLABS Interpretation = C.VIPS_INTERPRETATION_LABS
InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
InterpretationYXY Interpretation = C.VIPS_INTERPRETATION_YXY
InterpretationFourier Interpretation = C.VIPS_INTERPRETATION_FOURIER
InterpretationGrey16 Interpretation = C.VIPS_INTERPRETATION_GREY16
InterpretationMatrix Interpretation = C.VIPS_INTERPRETATION_MATRIX
InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
InterpretationHSV Interpretation = C.VIPS_INTERPRETATION_HSV
)
例子:
img.ToColorSpace(vips.InterpretationSRGB)
调整亮度、饱和度,色相
func (r *ImageRef) Modulate(brightness, saturation, hue float64) error
这个函数如传入参数,可以同时调整图片的亮度,饱和度和色相,brightness 和 saturation 保持为 1 表示不变,hue 色相的调整稍微复杂一些,是一个角度,如果传入 0 表示不变,所以:
当我们仅调节图片亮度时,应该传入 brightness ,保持 saturation 是 1 ,hue 是 0,例如:
img.Modulate(1.5, 1, 0)
| 原图 | 调整亮度后 |
|---|---|
![]() | ![]() |
当我们仅调节图片饱和度时,应该保持 brightness 是 1 ,仅传入 saturation ,hue 是 0,例如:
TODO
当我们仅调节图片色相时,应该保持 brightness 是 1,brightness 是 1,仅传入 hue ,例如:
TODO






