跳转到内容

15 分钟 Quickstart

复制本页

本节将经典的“读取 → 处理 → 导出”流程落地为一个可跨四个入口对照的任务:把 input.jpg 缩小到不超过 640 × 640,不放大小图,输出质量为 82 的 output.webp。

运行示例时,可以将自己的 JPEG 命名为 input.jpg;尺寸和画面不同会产生不同的输出数据。

夜色中亮起红色轮廓灯的苏州东方之门建筑与前景步道
输入:JPEG1938 × 1292,610,191 bytes
缩小到 640 像素边界内的苏州东方之门夜景 WebP
参考输出:WebP640 × 427,36,172 bytes,quality 82

参考输出由 govips v2.19.0 / libvips 8.17.3 实际生成。

运行命令

go run . input.jpg output/

完整源码

package main

import (
	"fmt"
	"os"

	"github.com/davidbyttow/govips/v2/vips"
	"github.com/webp-sh/vips-handbook/examples/internal/recipeutil"
)

func main() {
	if err := run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(args []string) error {
	if len(args) != 3 {
		return fmt.Errorf("usage: quickstart-thumbnail <input.jpg> <output-directory>")
	}
	inputPath, outputDir := args[1], args[2]
	if err := os.MkdirAll(outputDir, 0o755); err != nil {
		return err
	}

	if err := vips.Startup(nil); err != nil {
		return fmt.Errorf("start libvips: %w", err)
	}
	defer vips.Shutdown()

	image, err := vips.NewThumbnailFromFile(inputPath, 640, 640, vips.InterestingNone)
	if err != nil {
		return fmt.Errorf("create thumbnail: %w", err)
	}
	defer image.Close()

	output, err := recipeutil.ExportWebp(image, outputDir, "output.webp", 82, map[string]any{
		"width": 640, "height": 640, "crop": "none", "withoutEnlargement": true,
	})
	if err != nil {
		return err
	}
	if output.Width > 640 || output.Height > 640 {
		return fmt.Errorf("unexpected thumbnail dimensions: %dx%d", output.Width, output.Height)
	}
	if err := recipeutil.WriteResult(outputDir, "quickstart-thumbnail", inputPath, []recipeutil.Output{output}); err != nil {
		return err
	}

	fmt.Printf("quickstart-thumbnail: %dx%d, %d bytes\n", output.Width, output.Height, output.Size)
	return nil
}

至少确认 output.webp 存在且能被重新读取;宽和高都不超过 640;输入小于目标尺寸时没有被放大;输出格式确实是 WebP 而不是只改了扩展名。

  • 格式: WEBP
  • 尺寸: 640 × 427
  • 通道数: 3
  • 透明通道: 无
  • 文件大小: 36,172 字节
  • 生成环境: govips v2.19.0 / libvips 8.17.3

四段代码表达同一个产品目标,但不是逐行等价:govips 和 pyvips 直接调用 thumbnail 能力,sharp 用 resize({ fit: 'inside' }) 表达边界,CLI 则通过操作参数传递保存选项。

同一张 1938 × 1292 的 JPEG,目标都是放进 640 像素且不放大,WebP quality 82。2026-10-12 的执行结果:

入口 libvips 输出尺寸 字节数
govips v2.19.0 8.17.3 640 × 427 36,172
sharp 0.35.5 8.18.7 640 × 427 35,924
pyvips 3.2.0 8.17.3 640 × 427 39,228
vips CLI 8.17.3 8.17.3 640 × 427 39,228

尺寸、格式和“没有放大”是对齐的。字节数没有完全相同:sharp 的 libvips 比另外三个新一个次版本;pyvips 与 CLI 共享 8.17.3,字节数相同,但与 govips 的缩略图调用路径仍有差异。

继续阅读构建第一个完整图像 Pipeline,把输入检查、方向归一化、编码和结果验证拆成明确阶段。