格式探测、元数据读取与像素统计采样
在接收外部图片或执行条件分支前,程序通常需要先回答两类问题:
- 文件头级探测(Header Probe):这是什么格式?宽高、通道数、动图帧数、EXIF 方向(Orientation)和 ICC 配置文件是否存在?这类操作只解析容器头部,不解码完整像素。
- 像素级采样与统计(Pixel Sampling & Statistics):某个坐标点的 RGB 值是多少?全图平均亮度、对比度、信息熵或主色调是什么?这类操作会触发实际像素解码。
只读文件头探测格式与元数据
Section titled “只读文件头探测格式与元数据”libvips 打开图像时采用延迟读取,因此在调用 Width()、Height()、Bands()、Pages() 或 sharp(input).metadata() 时,解码器只读取文件头部字节即可返回结果,非常适合在上传网关做尺寸准入检查(如拒绝总像素超过上限的图片)。
在 govips 中,还可以先用 vips.DetermineImageType(buf) 根据魔数(Magic Bytes)识别格式,再用 vips.IsTypeSupported(imgType) 检查当前编译的 libvips 是否支持该格式。
package main
import ( "fmt" "os"
"github.com/davidbyttow/govips/v2/vips")
func main() { if err := vips.Startup(nil); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer vips.Shutdown()
image, err := vips.NewImageFromFile("input.jpg") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer image.Close()
fmt.Printf("format=%v size=%dx%d bands=%d alpha=%v icc=%v exif=%v pages=%d orientation=%d\n", vips.ImageTypes[image.Format()], image.Width(), image.Height(), image.Bands(), image.HasAlpha(), image.HasProfile(), image.HasExif(), image.Pages(), image.Orientation(), )}import sharp from 'sharp';
const meta = await sharp('input.jpg').metadata();
console.log({ format: meta.format, width: meta.width, height: meta.height, channels: meta.channels, space: meta.space, hasAlpha: meta.hasAlpha, hasProfile: meta.hasProfile, orientation: meta.orientation, pages: meta.pages ?? 1,});import pyvips
image = pyvips.Image.new_from_file("input.jpg")
print({ "loader": image.get("vips-loader"), "width": image.width, "height": image.height, "bands": image.bands, "interpretation": image.interpretation, "has_alpha": image.hasalpha(), "pages": image.get_n_pages(), "fields": image.get_fields()[:8],})#!/usr/bin/env bashset -euo pipefail
# 查看全部头部与元数据字段vipsheader -a input.jpg
# 仅读取单个字段(适合 Shell 脚本条件判断)vipsheader -f width input.jpgvipsheader -f height input.jpg元数据保留、定向清理与写入差异
Section titled “元数据保留、定向清理与写入差异”四个入口在导出时的默认元数据策略并不一致:
sharp默认剥离绝大多数元数据(EXIF、XMP、IPTC),以减小输出体积并保护隐私;若需保留,必须显式调用.keepMetadata()、.keepExif()、.keepIccProfile()或.withExifMerge()。govips、pyvips与vips CLI默认保留输入元数据;若需剥离,必须显式设置ExportParams.StripMetadata = true、调用image.RemoveMetadata(),或在保存参数中传入keep="none"(旧名strip=True)。
govips 的 image.RemoveMetadata(keepFields...) 允许传入白名单字段名——例如调用 image.RemoveMetadata("icc-profile-data") 可以清除所有相机 EXIF/GPS 隐私信息,同时完整保留决定颜色准确度的 ICC 配置文件。
// 清除所有 EXIF / XMP / IPTC 隐私元数据,但保留内嵌 ICC 配置文件if err := image.RemoveMetadata("icc-profile-data"); err != nil { return err}// sharp 默认剥离 EXIF;仅显式保留 ICC Profile 以确保广色域颜色不偏移await sharp('input.jpg') .keepIccProfile() .webp({ quality: 82 }) .toFile('clean-with-icc.webp');# 导出时仅保留 ICC Profile,剥离 EXIF、XMP 和 IPTCimage = pyvips.Image.new_from_file("input.jpg")image.write_to_file("clean-with-icc.webp", Q=82, keep="icc")vips copy input.jpg 'clean-with-icc.webp[Q=82,keep=icc]'单点像素取样与全局图像统计(GetPoint / Stats)
Section titled “单点像素取样与全局图像统计(GetPoint / Stats)”除头部信息外,libvips 还提供无需把整张图导出到业务层即可执行的像素采样与统计操作:
- 单点像素采样(
GetPoint/getpoint):读取指定坐标(x, y)的各通道数值,适合自动化测试断言、背景色吸管取色或边框颜色检测。 - 全局与通道统计(
Stats/Average/HistogramEntropy):计算全图最小值、最大值、均值、标准差与信息熵。其中sharp.stats()还会额外计算图像清晰度指标(sharpness)与主色调(dominantRGB)。
// 1. 读取坐标 (969, 646) 处的像素通道值 ([]float64)pixel, err := image.GetPoint(969, 646)if err != nil { return err}
// 2. 计算全图平均像素值、最小值与直方图信息熵avg, err := image.Average()if err != nil { return err}entropy, err := image.HistogramEntropy()if err != nil { return err}fmt.Printf("pixel(969,646)=%v avg=%.2f entropy=%.4f\n", pixel, avg, entropy)import sharp from 'sharp';
const stats = await sharp('input.jpg').stats();
console.log({ isOpaque: stats.isOpaque, entropy: stats.entropy, sharpness: stats.sharpness, dominant: stats.dominant, // { r, g, b } redMean: stats.channels[0].mean,});import pyvips
image = pyvips.Image.new_from_file("input.jpg")
pixel = image.getpoint(969, 646)avg = image.avg()std_dev = image.deviate()entropy = image.hist_entropy()print({"pixel": pixel, "avg": avg, "std": std_dev, "entropy": entropy})# 读取单个像素点 (969, 646) 的 RGB 值vips getpoint input.jpg 969 646
# 计算全图均值、标准差与信息熵vips avg input.jpgvips deviate input.jpgvips hist_entropy input.jpg| 探测或统计能力 | govips v2.20.0 | sharp 0.35.5 | pyvips 3.2.0 | vips CLI 8.17.3 |
|---|---|---|---|---|
| 魔数格式判断 | DetermineImageType(buf) |
(await sharp(buf).metadata()).format |
Image.find_load_buffer(buf) |
vipsheader -f vips-loader |
| 单点像素采样 | img.GetPoint(x, y) |
无独立方法(需 extract({ left: x, top: y, width: 1, height: 1 }).raw()) |
img.getpoint(x, y) 或 img(x, y) |
vips getpoint in x y |
| 全图均值 / 极值 | img.Average()、img.Min()、img.Stats() |
(await img.stats()).channels |
img.avg()、img.min()、img.max()、img.stats() |
vips avg、vips min、vips max、vips stats |
| 信息熵 / 主色调 | img.HistogramEntropy() |
stats.entropy、stats.dominant、stats.sharpness |
img.hist_entropy() |
vips hist_entropy |