强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

GraphicsMagick 图像处理完整教程 / 第06章 绘图与合成

第06章 绘图与合成

6.1 绘图基础

GraphicsMagick 的 -draw 参数使用类似 PostScript 的矢量绘图语法:

基本格式:
-draw "primitive 参数"

支持的绘图原语 (Primitives)

原语 说明 语法示例
point point x,y
line 线段 line x1,y1 x2,y2
rectangle 矩形 rectangle x1,y1 x2,y2
roundrectangle 圆角矩形 roundrectangle x1,y1 x2,y2 rx,ry
circle 圆形 circle cx,cy ex,ey
ellipse 椭圆 ellipse cx,cy rx,ry start,end
arc 弧线 arc x1,y1 x2,y2 start,end
polygon 多边形 polygon x1,y1 x2,y2 x3,y3 ...
polyline 折线 polyline x1,y1 x2,y2 ...
bezier 贝塞尔曲线 bezier x1,y1 x2,y2 x3,y3 ...
path SVG 路径 path 'M0,0 L100,100'
text 文字 text x,y 'Hello'
image 图像 image Over x,y w,h file

6.2 文字标注

6.2.1 基本文字绘制

# 基本文字
gm convert -font Helvetica -pointsize 36 \
  -fill white -draw "text 50,50 'Hello World'" \
  xc:'#333333' output.png

# 中文文字(需要中文字体)
gm convert -font "Noto-Sans-CJK-SC" -pointsize 48 \
  -fill '#FFFFFF' -draw "text 30,60 '你好世界'" \
  xc:'#2C3E50' output_cn.png

# 指定字体文件路径
gm convert -font /usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc \
  -pointsize 32 -fill white \
  -draw "text 20,40 '自定义字体'" \
  xc:'#1a1a2e' output.png

6.2.2 文字排版参数

参数 说明 示例
-font 字体名称或路径 -font Arial
-pointsize 字号(磅值) -pointsize 24
-fill 文字颜色 -fill '#FF0000'
-stroke 描边颜色 -stroke black
-strokewidth 描边宽度 -strokewidth 2
-gravity 对齐方式 -gravity center
-interline-spacing 行间距 -interline-spacing 10
-kerning 字间距 -kerning 2
-style 字体样式 -style Italic
-weight 字体粗细 -weight Bold
-underline 下划线 -underline
-encoding 编码 -encoding UTF-8

6.2.3 多行文字

# 方法 1:使用 \n
gm convert -font Helvetica -pointsize 24 \
  -fill white -gravity center \
  -draw "text 0,0 'Line 1\nLine 2\nLine 3'" \
  xc:'#333' multiline.png

# 方法 2:使用 -annotate
gm convert -font Helvetica -pointsize 24 \
  -fill white -gravity South \
  -annotate +0+20 "底部居中文字" \
  xc:'#333' annotate.png

6.2.4 文字特殊效果

# 阴影文字
gm convert -font Helvetica -pointsize 72 \
  -fill '#333333' -draw "text 3,3 'Shadow'" \
  -fill white -draw "text 0,0 'Shadow'" \
  xc:'#2C3E50' shadow_text.png

# 描边文字
gm convert -font Helvetica -pointsize 72 \
  -stroke black -strokewidth 3 -fill white \
  -draw "text 0,0 'Outlined'" \
  xc:'#3498DB' outlined_text.png

# 渐变文字效果(使用 mask)
gm convert -font Helvetica -pointsize 96 \
  -fill white -annotate +0+0 'Gradient' \
  gradient:'#FF6B6B'-'#4ECDC4' gradient_bg.png \
  -composite gradient_text.png

6.2.5 业务场景:动态生成标题图

#!/bin/bash
# generate_title.sh — 动态生成博客标题图
# 用法: ./generate_title.sh "文章标题" "副标题"

TITLE="$1"
SUBTITLE="$2"
WIDTH=1200
HEIGHT=630

gm convert -size "${WIDTH}x${HEIGHT}" \
  gradient:'#1a1a2e'-'#16213e' \
  -font "Noto-Sans-CJK-SC" -pointsize 52 \
  -fill '#E8E8E8' -gravity Center \
  -annotate +0-40 "$TITLE" \
  -pointsize 24 -fill '#AAAAAA' \
  -annotate +0+30 "$SUBTITLE" \
  "title_${WIDTH}x${HEIGHT}.png"

echo "标题图已生成: title_${WIDTH}x${HEIGHT}.png"

6.3 图形绘制

6.3.1 基本形状

# 矩形
gm convert -fill '#3498DB' -stroke white -strokewidth 2 \
  -draw "rectangle 50,50 250,150" \
  xc:'#2C3E50' rectangle.png

# 圆角矩形
gm convert -fill '#2ECC71' -stroke white -strokewidth 2 \
  -draw "roundrectangle 50,50 250,150 15,15" \
  xc:'#2C3E50' rounded_rect.png

# 圆形
gm convert -fill '#E74C3C' -stroke white -strokewidth 2 \
  -draw "circle 150,150 150,50" \
  xc:'#2C3E50' circle.png

# 椭圆
gm convert -fill '#9B59B6' -stroke white -strokewidth 2 \
  -draw "ellipse 200,150 120,60 0,360" \
  xc:'#2C3E50' ellipse.png

# 线段
gm convert -stroke '#F39C12' -strokewidth 3 \
  -draw "line 50,50 350,250" \
  xc:'#2C3E50' line.png

6.3.2 多边形

# 三角形
gm convert -fill '#1ABC9C' -stroke white -strokewidth 2 \
  -draw "polygon 200,50 100,250 300,250" \
  xc:'#2C3E50' triangle.png

# 五角星(使用路径)
gm convert -fill '#F1C40F' -stroke '#F39C12' -strokewidth 2 \
  -draw "polygon 200,40 230,130 320,130 245,185 270,275 200,220 130,275 155,185 80,130 170,130" \
  xc:'#2C3E50' star.png

6.3.3 绘图属性设置

# 设置不透明度
gm convert -fill 'rgba(255,0,0,0.5)' \
  -draw "rectangle 50,50 250,150" \
  xc:'#2C3E50' transparent_rect.png

# 设置线条虚线
gm convert -stroke white -strokewidth 2 \
  -dasharray 10,5 \
  -draw "line 50,50 350,250" \
  xc:'#2C3E50' dashed_line.png

6.4 水印制作

6.4.1 文字水印

# 单行文字水印
gm convert photo.jpg \
  -font Helvetica -pointsize 24 \
  -fill 'rgba(255,255,255,0.5)' \
  -gravity SouthEast -annotate +20+20 "© 2024 MySite" \
  output_watermark.jpg

# 重复平铺水印
gm convert photo.jpg \
  -font Helvetica -pointsize 48 \
  -fill 'rgba(255,255,255,0.15)' \
  -gravity Center -rotate 45 \
  -annotate +0+0 "CONFIDENTIAL" \
  output_tiled.jpg

6.4.2 图片水印

# 基本图片水印叠加
gm composite -dissolve 30 \
  -gravity SouthEast -geometry +20+20 \
  watermark.png photo.jpg output.jpg

# 平铺水印
gm composite -dissolve 15 \
  -tile watermark.png photo.jpg output.jpg

# 居中水印
gm composite -dissolve 40 \
  -gravity Center \
  watermark.png photo.jpg output.jpg

6.4.3 水印参数说明

参数 说明 示例
-dissolve N 透明度 (0-100) -dissolve 30 = 30% 不透明
-gravity 位置锚点 -gravity SouthEast
-geometry +X+Y 偏移量 -geometry +20+20
-tile 平铺模式 -tile
-watermark N% 水印强度 -watermark 30%
-compose 合成模式 -compose Over

6.4.4 业务场景:批量添加水印

#!/bin/bash
# batch_watermark.sh
# 批量为目录中的图片添加水印

WATERMARK="watermark.png"
INPUT_DIR="input/"
OUTPUT_DIR="watermarked/"
DISSOLVE=30

mkdir -p "$OUTPUT_DIR"

for img in "$INPUT_DIR"*.{jpg,jpeg,png}; do
  [ -f "$img" ] || continue
  filename=$(basename "$img")
  echo "处理: $filename"
  gm composite -dissolve "$DISSOLVE" \
    -gravity SouthEast -geometry +20+20 \
    "$WATERMARK" "$img" \
    "$OUTPUT_DIR$filename"
done

echo "批量水印完成!共处理 $(ls "$OUTPUT_DIR" | wc -l) 张图片"

6.5 图像合成 (Composite)

6.5.1 合成模式 (Compose Operators)

模式 说明 典型用途
Over 覆盖(默认) 叠加图层
In 交集(仅重叠部分) 蒙版效果
Out 差集(仅非重叠部分) 镂空效果
Atop 在上面(含背景) 合成
Xor 异或 特殊效果
Plus 相加 亮度叠加
Minus 相减 差异检测
Multiply 正片叠底 加深效果
Screen 滤色 减淡效果
Overlay 叠加 增强对比
Dissolve 溶解 半透明叠加
Modulate 调制 亮度调整
CopyOpacity 复制透明度 蒙版
Difference 差值 图像对比
Hue 色相 颜色替换
Saturation 饱和度 颜色调整
Colorize 着色 色彩叠加

6.5.2 合成示例

# 基本叠加
gm composite overlay.png base.jpg output.jpg

# 使用指定合成模式
gm composite -compose Multiply overlay.png base.jpg output.jpg

# 使用蒙版(透明度)
gm composite -compose CopyOpacity mask.png base.jpg output.png

# 差异对比(找不同)
gm composite -compose Difference img1.jpg img2.jpg diff.jpg

6.5.3 双图合成场景

# 场景:前后对比图
gm montage -label "Before" before.jpg \
           -label "After" after.jpg \
           -tile 2x1 -geometry 600x400+5+5 \
  -background '#333' comparison.jpg

# 场景:A/B 测试对比
gm convert before.jpg after.jpg +append comparison.jpg

6.6 图像拼接与画布操作

6.6.1 创建画布

# 纯色画布
gm convert -size 800x600 xc:'#2C3E50' canvas.png

# 透明画布
gm convert -size 800x600 xc:none canvas_transparent.png

# 渐变画布
gm convert -size 800x600 gradient:'#FF6B6B'-'#4ECDC4' gradient_canvas.png

# 径向渐变
gm convert -size 800x600 \
  radial-gradient:'#FFFFFF'-'#000000' \
  radial_canvas.png

6.6.2 多图拼接

# 水平拼接(相同高度)
gm convert img1.jpg img2.jpg img3.jpg +append horizontal.jpg

# 垂直拼接(相同宽度)
gm convert img1.jpg img2.jpg img3.jpg -append vertical.jpg

# 网格拼接(使用 montage)
gm montage -tile 3x2 -geometry 300x200+5+5 \
  -background '#222' *.jpg grid.jpg

# 带标题的网格
gm montage -label '%f' -tile 3x2 \
  -geometry 300x200+5+5 \
  -background '#222' -fill white \
  *.jpg titled_grid.jpg

6.7 图层操作

6.7.1 使用 -page 控制图层位置

# 将图像放置在指定位置
gm convert \
  -size 800x600 xc:'#2C3E50' \
  -page +50+50 small_img1.jpg \
  -page +400+300 small_img2.jpg \
  -layers merge output.jpg

6.7.2 平铺背景

# 创建重复平铺图案
gm convert -size 100x100 \
  -fill '#3498DB' -draw "rectangle 0,0 50,50" \
  -fill '#2980B9' -draw "rectangle 50,50 100,100" \
  pattern_tile.png

# 平铺为背景
gm convert pattern_tile.png -resize 800x600! tiled_bg.png

6.8 注解与标签

6.8.1 -annotate 参数

# annotate 基本用法
# -annotate X旋转xY旋转 +X偏移+Y偏移 "文字"

# 无旋转,偏移 (0,0)
gm convert -font Helvetica -pointsize 36 -fill white \
  -annotate +0+0 "Center Text" \
  xc:'#333' annotated.png

# 旋转 45 度
gm convert -font Helvetica -pointsize 36 -fill white \
  -annotate 45x45+0+0 "Rotated" \
  xc:'#333' rotated_text.png

# 使用 gravity 定位
gm convert -font Helvetica -pointsize 24 -fill white \
  -gravity NorthWest -annotate +20+20 "Top Left" \
  -gravity SouthEast -annotate +20+20 "Bottom Right" \
  xc:'#333' corner_text.png

6.8.2 自动编号标注

#!/bin/bash
# label_images.sh — 为图片批量添加编号标签

OUTPUT_DIR="labeled/"
mkdir -p "$OUTPUT_DIR"
i=1

for img in *.jpg; do
  [ -f "$img" ] || continue
  gm convert "$img" \
    -fill 'rgba(0,0,0,0.6)' \
    -draw "rectangle 0,0 60,30" \
    -font Helvetica -pointsize 18 -fill white \
    -gravity NorthWest -annotate +10+5 "#${i}" \
    "$OUTPUT_DIR$img"
  ((i++))
done

6.9 高级合成技巧

6.9.1 圆形头像

# 创建圆形裁剪蒙版
gm convert -size 200x200 \
  xc:none -fill white \
  -draw "circle 100,100 100,0" \
  mask_circle.png

# 应用蒙版
gm convert input.jpg -resize 200x200! +profile '*' /tmp/resized.jpg
gm composite -compose CopyOpacity mask_circle.png /tmp/resized.jpg avatar.png

# 添加圆形边框
gm convert avatar.png \
  -bordercolor none -border 4 \
  \( -size 208x208 xc:none -fill none \
     -stroke '#3498DB' -strokewidth 4 \
     -draw "circle 104,104 104,0" \) \
  -composite avatar_bordered.png

6.9.2 图片倒影效果

#!/bin/bash
# reflection.sh — 生成图片倒影效果
INPUT="$1"
OUTPUT="reflection_$(basename $INPUT)"

# 获取尺寸
W=$(gm identify -format "%w" "$INPUT")
H=$(gm identify -format "%h" "$INPUT")
REFLECT_H=$((H / 3))
TOTAL_H=$((H + REFLECT_H + 10))

# 创建倒影
gm convert "$INPUT" \
  -flip -resize "${W}x${REFLECT_H}!" \
  -level 0%,100%,0.5 \
  /tmp/reflection.png

# 合成
gm convert -size "${W}x${TOTAL_H}" xc:'#2C3E50' \
  "$INPUT" -geometry +0+0 -composite \
  /tmp/reflection.png -geometry +0+${H} -composite \
  "$OUTPUT"

rm -f /tmp/reflection.png
echo "倒影效果已生成: $OUTPUT"

6.10 绘图操作速查表

操作 命令
矩形 -draw "rectangle x1,y1 x2,y2"
圆形 -draw "circle cx,cy ex,ey"
线段 -draw "line x1,y1 x2,y2"
文字 -draw "text x,y 'text'"
水印 -annotate +X+Y "text"
图片叠加 gm composite overlay base output
平铺叠加 gm composite -tile overlay base output
水平拼接 gm convert a.jpg b.jpg +append out.jpg
垂直拼接 gm convert a.jpg b.jpg -append out.jpg
创建画布 -size WxH xc:COLOR
渐变画布 -size WxH gradient:c1-c2

6.11 本章小结

要点 说明
-draw 是绘图核心 支持矩形、圆形、多边形、文字等
文字标注用 -annotate 更灵活的定位和旋转
水印用 gm composite 支持 dissolve 透明度和 tile 平铺
合成模式丰富 Over、Multiply、Screen 等
蒙版实现裁剪效果 CopyOpacity 模式
中文需要 CJK 字体 确保安装了中文字体包

扩展阅读

  1. GraphicsMagick Draw 命令参考
  2. GraphicsMagick Composite 参考
  3. SVG Path 语法
  4. 图像合成模式详解
  5. CSS Blend Modes(类比理解)

上一章第05章 颜色处理 下一章第07章 图像特效