第04章 几何变换
第04章 几何变换
4.1 几何参数语法
GraphicsMagick 使用统一的 Geometry 字符串 来描述尺寸、位置和偏移量:
标准格式:[WxH][+X+Y][!@%<>^]
W — 宽度
H — 高度
X — X 偏移
Y — Y 偏移
! — 强制忽略宽高比
@ — 按像素总数缩放
% — 按百分比缩放
> — 仅缩小(大于目标尺寸时)
< — 仅放大(小于目标尺寸时)
^ — 填充裁剪(保证覆盖目标区域)
Geometry 示例
| 表达式 | 含义 |
|---|---|
800 | 宽度 800,高度按比例 |
x600 | 高度 600,宽度按比例 |
800x600 | 限制在 800×600 范围内,保持比例 |
800x600! | 强制缩放到 800×600(可能变形) |
800x600> | 仅当原图大于 800×600 时缩放 |
800x600< | 仅当原图小于 800×600 时放大 |
800x600^ | 保证覆盖 800×600 区域(可能超出) |
800x600+100+50 | 800×600,偏移 (100,50) |
50% | 缩放到 50% |
120000@ | 缩放到约 120000 像素总数 |
4.2 缩放 (Resize)
4.2.1 基本缩放
# 按宽度缩放(高度自动计算)
gm convert -resize 800 input.jpg output.jpg
# 按高度缩放
gm convert -resize x600 input.jpg output.jpg
# 按百分比缩放
gm convert -resize 50% input.jpg output.jpg
gm convert -resize 200% input.jpg output.jpg
# 指定最大范围(保持比例)
gm convert -resize "800x600" input.jpg output.jpg
4.2.2 缩放模式详解
# 模式 1:保持比例,限制最大尺寸
# 原图 1920x1080 → 输出 800x450
gm convert -resize "800x600" input.jpg output.jpg
# 模式 2:强制指定尺寸(可能变形)
# 原图 1920x1080 → 输出 800x600(拉伸)
gm convert -resize "800x600!" input.jpg output.jpg
# 模式 3:仅缩小(大于目标时才处理)
# 原图 1920x1080 → 输出 800x450(缩小)
# 原图 400x300 → 输出 400x300(不变)
gm convert -resize "800x600>" input.jpg output.jpg
# 模式 4:仅放大(小于目标时才处理)
# 原图 400x300 → 放大到 800x600
# 原图 1920x1080 → 不变
gm convert -resize "800x600<" input.jpg output.jpg
# 模式 5:填充裁剪(保证覆盖目标区域,可能裁掉边缘)
# 原图 1920x1080 (16:9) → 目标 800x600 (4:3)
# 先缩放到 1067x600(覆盖 800x600),再裁掉多余部分
gm convert -resize "800x600^" \
-gravity center -extent "800x600" \
input.jpg output.jpg
4.2.3 缩放质量与滤波器
# 默认使用 Lanczos 滤波器(高质量)
# 指定不同的插值滤波器
gm convert -filter Lanczos -resize 50% input.jpg output.jpg
gm convert -filter Mitchell -resize 50% input.jpg output.jpg
gm convert -filter Catrom -resize 50% input.jpg output.jpg
gm convert -filter Gaussian -resize 50% input.jpg output.jpg
gm convert -filter Box -resize 50% input.jpg output.jpg
gm convert -filter Point -resize 50% input.jpg output.jpg
| 滤波器 | 质量 | 速度 | 适用场景 |
|---|---|---|---|
| Lanczos | ⭐⭐⭐⭐⭐ | 慢 | 高质量缩放(默认) |
| Mitchell | ⭐⭐⭐⭐ | 中 | 平滑缩小 |
| Catrom | ⭐⭐⭐⭐ | 中 | 锐利缩小 |
| Gaussian | ⭐⭐⭐ | 中 | 模糊缩放效果 |
| Box | ⭐⭐ | 快 | 快速缩小(整数倍) |
| Point | ⭐ | 最快 | 像素艺术(最近邻) |
| Sinc | ⭐⭐⭐⭐⭐ | 最慢 | 理论最优(振铃效应) |
4.2.4 业务场景:Web 响应式图片
#!/bin/bash
# generate_responsive.sh
# 为响应式 Web 设计生成多尺寸图片
INPUT="$1"
BASENAME=$(basename "${INPUT%.*}")
# 响应式断点
declare -A BREAKPOINTS=(
["xs"]="480" # 手机
["sm"]="768" # 平板竖屏
["md"]="1024" # 平板横屏
["lg"]="1440" # 桌面
["xl"]="1920" # 大屏
)
for name in "${!BREAKPOINTS[@]}"; do
width="${BREAKPOINTS[$name]}"
gm convert "$INPUT" \
-filter Lanczos \
-resize "${width}>" \
-quality 85 \
-strip \
"output_${BASENAME}_${name}.jpg"
size=$(gm identify -format "%b" "output_${BASENAME}_${name}.jpg")
echo "${name} (${width}px): ${size}"
done
4.3 裁剪 (Crop)
4.3.1 基本裁剪
# 从左上角 (0,0) 裁剪 400x300 区域
gm convert -crop 400x300+0+0 input.jpg output.jpg
# 从指定位置开始裁剪
gm convert -crop 400x300+100+50 input.jpg output.jpg
# 从中心裁剪
gm convert -gravity center -crop 400x300+0+0 input.jpg output.jpg
4.3.2 Gravity 锚点
-gravity 参数设置裁剪的参考锚点:
NorthWest (左上) North (上) NorthEast (右上)
West (左) Center (中) East (右)
SouthWest (左下) South (下) SouthEast (右下)
# 从右下角裁剪
gm convert -gravity SouthEast -crop 200x200+0+0 input.jpg output.jpg
# 从顶部中心裁剪(适合人像去底部)
gm convert -gravity North -crop 800x400+0+0 portrait.jpg output.jpg
4.3.3 自动裁剪
# 自动去除边缘空白/纯色边框
gm convert -trim input.jpg output.jpg
# 带容差的 trim(允许颜色微小差异)
gm convert -fuzz 5% -trim input.jpg output.jpg
# 增加 trim 后的边距
gm convert -trim +repage -bordercolor white -border 20 input.jpg output.jpg
4.3.4 业务场景:智能裁剪头像
#!/bin/bash
# crop_avatar.sh — 将照片裁剪为正方形头像
# 用法: ./crop_avatar.sh input.jpg 200
INPUT="$1"
SIZE="${2:-200}"
# 获取原始尺寸
WH=$(gm identify -format "%wx%h" "$INPUT")
W=$(echo $WH | cut -dx -f1)
H=$(echo $WH | cut -dx -f2)
# 计算裁剪区域(取短边为基准)
if [ "$W" -gt "$H" ]; then
OFFSET=$(( (W - H) / 2 ))
CROP="${H}x${H}+${OFFSET}+0"
else
OFFSET=$(( (H - W) / 2 ))
CROP="${W}x${W}+0+${OFFSET}"
fi
gm convert "$INPUT" \
-crop "$CROP" \
-resize "${SIZE}x${SIZE}!" \
-quality 90 \
"avatar_${SIZE}.jpg"
echo "已生成 ${SIZE}x${SIZE} 头像: avatar_${SIZE}.jpg"
4.4 旋转 (Rotate)
4.4.1 基本旋转
# 顺时针旋转 90°
gm convert -rotate 90 input.jpg output.jpg
# 旋转 180°(倒置)
gm convert -rotate 180 input.jpg output.jpg
# 逆时针旋转 90°(即 270°)
gm convert -rotate 270 input.jpg output.jpg
gm convert -rotate "-90" input.jpg output.jpg
# 自由角度旋转
gm convert -rotate 30 input.jpg output.jpg
4.4.2 旋转与背景色
自由角度旋转后,空白区域会填充背景色:
# 默认黑色背景
gm convert -rotate 30 input.jpg output.jpg
# 指定白色背景
gm convert -background white -rotate 30 input.jpg output.jpg
# 透明背景(需要 PNG 格式)
gm convert -background none -rotate 30 input.jpg output.png
# 指定任意颜色
gm convert -background '#FF6B6B' -rotate 45 input.jpg output.jpg
4.4.3 自动旋转(EXIF 方向)
数码相机拍摄的照片通常包含 EXIF 方向标记:
# 根据 EXIF 信息自动校正方向
gm convert -auto-orient input.jpg output.jpg
# 查看 EXIF 方向
gm identify -verbose input.jpg | grep -i "orientation"
| EXIF 方向值 | 含义 | 需要的操作 |
|---|---|---|
| 1 | 正常 | 无 |
| 2 | 水平翻转 | -flop |
| 3 | 旋转 180° | -rotate 180 |
| 4 | 垂直翻转 | -flip |
| 5 | 顺时针 90° + 水平翻转 | -rotate 90 -flop |
| 6 | 顺时针 90° | -rotate 90 |
| 7 | 逆时针 90° + 水平翻转 | -rotate -90 -flop |
| 8 | 逆时针 90° | -rotate -90 |
4.5 翻转 (Flip & Flop)
# 垂直翻转(上下颠倒)
gm convert -flip input.jpg output.jpg
# 水平翻转(左右镜像)
gm convert -flop input.jpg output.jpg
# 同时翻转(等价于旋转 180°)
gm convert -flip -flop input.jpg output.jpg
4.6 扩展与填充 (Extent & Border)
4.6.1 Extent — 扩展画布
# 扩展画布到指定大小(锚点控制方向)
# 在底部添加空白
gm convert -gravity North -extent 800x1000 \
-background white input.jpg output.jpg
# 居中扩展,四周添加边距
gm convert -gravity center -extent 1000x800 \
-background '#f0f0f0' input.jpg output.jpg
4.6.2 Border — 添加边框
# 添加 10px 灰色边框
gm convert -border 10 -bordercolor gray input.jpg output.jpg
# 不对称边框
gm convert -border 20x10 -bordercolor black input.jpg output.jpg
# 20x10 表示左右各20px,上下各10px
4.7 仿射变换 (Affine Transform)
仿射变换包括缩放、旋转、剪切和平移的组合:
# 使用 -affine 和 -transform 进行仿射变换
# 参数: sx rx ry sy tx ty
# sx,sy — 缩放因子
# rx,ry — 旋转/剪切因子
# tx,ty — 平移量
# 示例:缩放 + 旋转
gm convert \
-affine 0.866,0.5,-0.5,0.866,0,0 \
-transform input.jpg output.jpg
# 示例:水平剪切 (Shear)
gm convert -shear 30x0 input.jpg output.jpg
# 示例:垂直剪切
gm convert -shear 0x30 input.jpg output.jpg
# 示例:同时水平和垂直剪切
gm convert -shear 20x15 input.jpg output.jpg
4.8 透视变换 (Perspective)
透视变换可以校正拍摄角度导致的变形:
# 使用 -distort Perspective 进行透视校正
# 需要指定 4 个源点和 4 个目标点
# 示例:校正倾斜拍摄的文档
gm convert \
-distort Perspective \
"0,0 50,10 300,0 280,30 300,400 290,380 0,400 30,390" \
input.jpg output.jpg
# Point 格式:src_x,src_y dst_x,dst_y
# 四个角的映射关系
透视变换参数说明
原始图四个角 目标图四个角
(0,0)──────(W,0) → (x1,y1)──────(x2,y2)
│ │ │ │
│ │ │ │
(0,H)──────(W,H) → (x3,y3)──────(x4,y4)
4.9 卷曲与变形 (Distort)
GraphicsMagick 支持多种 distortion(扭曲)模式:
# 查看支持的 distort 方法
gm convert -list distort
# Barrel 桶形畸变校正
gm convert -virtual-pixel edge \
-distort Barrel "0.1 0.0 0.0 1.0" \
input.jpg output.jpg
# BarrelInverse 枕形畸变
gm convert -virtual-pixel edge \
-distort BarrelInverse "0.1 0.0 0.0 1.0" \
input.jpg output.jpg
4.10 综合实战
场景:电商商品图片标准化
#!/bin/bash
# product_standardize.sh
# 电商商品图片标准化处理
INPUT="$1"
OUTPUT_DIR="product_output"
mkdir -p "$OUTPUT_DIR"
BASENAME=$(basename "${INPUT%.*}")
echo "处理: $INPUT"
# 步骤 1:自动旋转(EXIF 校正)
gm convert -auto-orient "$INPUT" /tmp/oriented.jpg
# 步骤 2:智能裁剪为正方形
WH=$(gm identify -format "%wx%h" /tmp/oriented.jpg)
W=$(echo $WH | cut -dx -f1)
H=$(echo $WH | cut -dx -f2)
if [ "$W" -gt "$H" ]; then
gm convert -gravity center -crop "${H}x${H}+0+0" +repage \
/tmp/oriented.jpg /tmp/cropped.jpg
else
gm convert -gravity center -crop "${W}x${W}+0+0" +repage \
/tmp/oriented.jpg /tmp/cropped.jpg
fi
# 步骤 3:生成多种尺寸
for size in 400 800 1200; do
gm convert /tmp/cropped.jpg \
-filter Lanczos \
-resize "${size}x${size}!" \
-quality 90 \
-strip \
-background white \
-gravity center \
-extent "${size}x${size}" \
"$OUTPUT_DIR/${BASENAME}_${size}.jpg"
echo " ✅ ${size}x${size} 已生成"
done
# 清理临时文件
rm -f /tmp/oriented.jpg /tmp/cropped.jpg
echo "完成!文件输出到 $OUTPUT_DIR/"
4.11 变换操作速查表
| 操作 | 命令 | 说明 |
|---|---|---|
| 等比缩放 | -resize 800 | 按宽度等比 |
| 百分比缩放 | -resize 50% | 按百分比 |
| 强制尺寸 | -resize 800x600! | 可能变形 |
| 仅缩小 | -resize 800x600> | 大于才缩 |
| 仅放大 | -resize 800x600< | 小于才放 |
| 填充裁剪 | -resize 800x600^ + -extent | 覆盖后裁 |
| 固定裁剪 | -crop 400x300+X+Y | 区域裁剪 |
| 居中裁剪 | -gravity center -crop 400x300+0+0 | 中心裁 |
| 自动去边 | -trim | 去纯色边 |
| 旋转 | -rotate 90 | 顺时针度数 |
| EXIF 旋转 | -auto-orient | 自动校正 |
| 垂直翻转 | -flip | 上下颠倒 |
| 水平翻转 | -flop | 左右镜像 |
| 剪切 | -shear 30x0 | 水平剪切 |
| 扩展画布 | -extent WxH | 扩展到 |
| 添加边框 | -border N | N像素边框 |
4.12 本章小结
| 要点 | 说明 |
|---|---|
| Geometry 字符串是核心语法 | WxH+X+Y!@%<>^ |
> 和 < 很常用 | Web 图片处理中避免放大很重要 |
-gravity 控制锚点 | 裁剪/扩展时至关重要 |
-auto-orient 处理手机照片 | 几乎所有上传处理都应加上 |
-resize 选对滤波器 | Lanczos 是默认高质量选择 |
| 仿射/透视变换更高级 | 文档校正、畸变校正等场景 |