为图像添加标注:ImageMagick示例
本文介绍如何用文字或其他图像为大图添加标注。标注可以醒目突出,也可以细微隐蔽。添加标注的原因很多,通常包括:
-
用信息说明图像的内容。
-
指出或突出图像的某个部分。
-
添加版权文字或标志,作为复制保护的方式。
ImageMagick提供了许多方法,但单靠手册不一定容易发现。本文介绍常用做法,其中不少方法会在其他示例页面中深入讨论。如果你想为GIF动画添加标注或水印,建议先阅读本文,再查看动画标注。
为图像添加标注
给图像加标签的基本难点,是让文字在任何图像背景上都清晰可读。下面介绍多种方法,有些还能扩展到更复杂的任务。这些示例仅使用ImageMagick的默认字体;你可以按目标选择其他字体和字号。
在图像下方或上方添加标签
拼接居中的标签。 从IM v6.4.7-1起,图像拼接会遵循gravity对齐设置,因此可以将标签居中拼接到图像上。
magick dragon.gif -background Khaki label:'Faerie Dragon' \
-gravity Center -append anno_label.jpg

改变图像顺序,就能把标签拼接到图像上方。
magick dragon.gif -background Orange label:'Faerie Dragon' \
+swap -gravity Center -append anno_label2.jpg

扩展画布后绘制。 splice与绘图结合,是为图像增加空间,再在其中绘制标签的简单方法。
magick dragon.gif \
-gravity South -background Plum -splice 0x18 \
-annotate +0+2 'Faerie Dragon' anno_splice.gif

同样可以在图像上方绘制标签,只需把gravity从South改为North。
magick dragon.gif \
-gravity North -background YellowGreen -splice 0x18 \
-annotate +0+2 'Faerie Dragon' anno_splice2.gif

除非是复杂绘图操作的一部分,否则不再建议用-draw直接绘制文字。其他文字绘制方法与技巧,详见文字转图像。
用montage添加标签。 用户往往认为montage只能把整个目录的图片排列成展示图,因而忽略它。实际上,它也提供了极其简单的图像标签功能。
montage -label "Faerie Dragon" dragon.gif \
-geometry +0+0 -background Gold anno_montage.jpg

montage还能为图像添加边框等效果,因此除了简单标签之外,还有许多扩展可能。
montage -label "Faerie Dragon" dragon.gif \
-font Candice -pointsize 15 \
-frame 5 -geometry +0+0 anno_montage2.jpg

有关montage的更多用法,参见示例索引中的“Montage, Arrays of Images”。
使用拍立得效果。 除了montage,还可以通过Polaroid图像变换生成带有精致说明的图片。
magick -caption "Faerie Dragon" dragon.gif -gravity center \
-background black +polaroid anno_polaroid.png

注意,这种变换会弯曲并旋转图像,而且带有随机性;除非禁用旋转,否则最终尺寸可能变化。结果还包含复杂的阴影和透明效果,因此这里使用PNG保存。
可以用超采样减少旋转带来的模糊;原文链接的Polaroid变换示例介绍了这种方法。
直接在图像上添加标签
直接把文字写在图像上的问题是:你无法保证所选文字颜色始终可读,背景可能是黑色、白色,也可能五颜六色。
描边标签。 最简单的办法是给文字描边,把它与图像区分开。不过,-stroke会同时向字体内外增加粗度,降低效果。因此,为文字绘制背景轮廓时,更好的办法是绘制两次文字。
magick dragon.gif -gravity south \
-stroke '#000C' -strokewidth 2 -annotate 0 'Faerie Dragon' \
-stroke none -fill white -annotate 0 'Faerie Dragon' \
anno_outline.jpg

这种方法可以工作,但效果并不理想。较粗的字体通常比默认的Times或Arial更合适。更详细的例子见原文链接的“Thick Stroke Compound Font”。
绘制暗色底框。 更传统的办法是先把文字区域变暗,再用相反的颜色绘制文字。例如:
magick dragon.gif \
-fill '#0008' -draw 'rectangle 5,128,114,145' \
-fill white -annotate +10+141 'Faerie Dragon' \
anno_dim_draw.jpg

这种方法效果不错。不过,此例没有用-gravity定位文字,因为暗色矩形不能按gravity定位,未来也许会改变。此外,矩形的大小和位置取决于图像与最终文字尺寸,可能需要额外计算。
文字底色框。 不必自己绘制背景框,可以让ImageMagick使用文字底色。库API中的undercolor,在命令行上通过-undercolor指定。相关说明见文字处理。
magick dragon.gif -fill white -undercolor '#00000080' -gravity South \
-annotate +0+5 ' Faerie Dragon ' anno_undercolor.jpg

这比自己绘制暗色框简单得多。建议在文字前后各加一个空格,让底框稍微宽一些。
合成标签。 更理想的方法是先生成文字图像,再把它叠加到原图。这里创建带半透明背景的标签,并将它合成到图像上。
magick -background '#00000080' -fill white label:'Faerie Dragon' miff:- |\
magick composite -gravity south -geometry +0+3 \
- dragon.gif anno_composite.jpg

这种方法有明显优势:暗色框可以自动适配标签大小,也可以用-gravity正确定位,无须事先知道背景图尺寸或文字字体的具体信息。
标签也不必局限于简单的暗色框。可以预先生成复杂的字体图像重复使用,也可以针对每张图即时生成。几乎所有复合字体效果都可应用于此,让添加的文字更丰富、更专业。
自动调整字号的说明文字。 从IM v6.3.2起,caption:能够自动调整文字大小,使其尽量适配给定尺寸的矩形。
要把它用作叠加层,需要先知道背景图的宽度。这里先获取宽度,再生成并叠加说明文字,让文字自动换行并适配指定空间。
width=`identify -format %w dragon.gif`; \
magick -background '#0008' -fill white -gravity center -size ${width}x30 \
caption:"Faerie Dragons love hot apple pies\!" \
dragon.gif +swap -gravity south -composite anno_caption.jpg

这种方法非常适合将图像注释叠加到原图上。但命令行处理时也会遇到问题,因为你正在创建新图,而非直接标注旧图。可参考原文的“User defined option escapes”链接。
花式标签。 最后这个例子使用柔和描边的文字,让标注保持可见,同时不产生矩形底框。
magick -size 100x14 xc:none -gravity center \
-stroke black -strokewidth 2 -annotate 0 'Faerie Dragon' \
-background none -shadow 100x3+0+0 +repage \
-stroke none -fill white -annotate 0 'Faerie Dragon' \
dragon.gif +swap -gravity south -geometry +0-3 \
-composite anno_fancy.jpg

如果打算把同一标签,例如版权说明,合成到大量图像上,最好单独生成标签,再用mogrify合成到每张图。上例中的-geometry +0-3使叠加层更靠近边缘,因为柔和轮廓往往比实际需要的范围更大。
所有示例都应按自己的需求调整。不要只是照搬别人的做法;多做实验,让你的网站或程序拥有自己的特点,也欢迎把方法分享给IM社区。
后续设想:根据图像的相对亮度选择黑色或白色文字,需要组合几种高级技巧。
magick input.jpg -font myfont -pointsize 25 \
\( +clone -resize 1x1 -fx 1-intensity -threshold 50% \
-scale 32x32 -write mpr:color +delete \) -tile mpr:color \
-annotate +10+26 'My Text' output.jpg

解释:将图像副本缩小到1像素,取得平均颜色;再通过-fx反相并灰度化,用阈值转换成合适的黑色或白色。
随后把这个单色像素放大为可平铺的图像,保存到命名内存寄存器mpr:中。
最后用该图像设置标注文字的填充纹理。但在原文所述时期,尚无简单方法把文字的-stroke颜色设为其反色。
其他方法包括将文字作为反相图像的蒙版,或使用颜色加深、颜色减淡等合成操作,以文字形状改变图像。
叠加图像
ImageMagick的magick composite命令和-composite图像运算符,是以各种方式将图像叠加到其他图像上的主要手段。详细方法见Alpha合成示例。一些更高级操作也依赖Alpha合成,包括图像图层,以及下文的gravity定位。
默认合成方式是Over,它把前景叠加到背景上,并按预期处理透明度。最终尺寸由背景图决定,无论使用-geometry把前景放在何处都一样:位于中央、半截超出背景,甚至远在背景之外,输出仍与背景尺寸相同。
图像的几何位置也受-gravity影响,可以相对于九个不同方位定位,详见下文“定位图像和文字”。除叠加层的-geometry外,各图像还可以具有由-page、-repage设置的页面或画布信息,影响最终位置。
但这种图像自身的信息不受-gravity影响。来看示例:叠加可能是最常见的标注形式,也很简单。这里把32×32的城堡图标放在预先准备的按钮边框中央。
magick composite -gravity center castle.gif frame.gif castle_button.gif

还可以精确定位子图像。这里用一只手指向精灵龙的小爪子。
magick composite -geometry +31+105 hand_point.gif dragon.gif \
dragon_claw_pointed.jpg

前景如何绘制到背景上,由-compose设置控制。默认的-compose over只是覆盖图像。其他大多数合成方式只在特定场景适用,下面介绍其中几种;详见Alpha合成。
Bumpmap。 这种合成方式有些特别,基本上会根据前景亮度使背景变暗。前景中的白色被当作透明处理,黑色会使输出变黑,可以把它想象成用前景盖上墨水印章。浅色图像通常更适合这种方法,因此使用前可能需要准备bumpmap图像。
这里先缩小龙的图像,再使用-compose bumpmap将它印到卷轴上。
magick composite \( dragon.gif -resize 50% \) scroll.gif \
-compose bumpmap -gravity center dragon_scroll.gif

Bumpmap也能给整幅图增加效果。这里把浅色背景纹理平铺到龙的图像上。记住,bumpmap会把前景当作灰度图,所以叠加图中的颜色会丢失。
magick composite -compose bumpmap -tile rings.jpg \
dragon.gif dragon_rings.jpg

上面的-tile只适用于magick composite命令的合成操作。使用magick时,需要用tile:图像生成器,并通过-size指定范围。前景可以比背景更大,因为输出仍以背景或目标图像尺寸为准。
Multiply。 正片叠底最常用于合并两张白底图像,例如把图叠加到文字页面上。与bumpmap不同,它不会先把前景转换成灰度。
mesgs PictureWords |\
magick -pointsize 18 text:- -trim +repage \
-bordercolor white -border 10x5 text.gif
magick composite -compose multiply -geometry +400+3 \
paint_brush.gif text.gif text_multiply.gif


补充:上面生成text.gif的复杂命令只是为了构造一张典型的纯文字图像。mesgs输出指定引文,类似fortune,但控制更灵活。这种方法在许多情况下都很有效,不过通常要求至少一张图基本上是白底黑色或灰度内容。如果两张图都含有彩色区域,结果可能不太寻常。
也就是说,它很适合把线稿、示意图或文字图像叠加到白色或较浅的背景上,例如打印或扫描页面。
水印
水印可以表明图像属于某家公司或网站,但遗憾的是,它总会以某种方式损伤图像。水印的基本目标是:
-
无论背景明暗,标记都清晰可见。
-
难以擦除。
-
不至于让观看者过于反感。
这些目标相互冲突,也是水印难以做好的原因之一。
符号水印
最简单、也最容易令人反感的水印形式之一,是在图像某处放置一个很小但独特的图标。这里用logo:生成待加水印的图像,再叠加一对小眼睛。
magick logo: -resize x180 -gravity center -crop 180x180+0+0 logo.jpg
magick composite -geometry +160+13 eyes.gif logo.jpg wmark_symbol.jpg


最好的放置方式是让图标看起来像原图的一部分。这里的眼睛似乎属于巫师的帽子,但也不能融入得完全看不出来。这需要人的判断,因此难以完全自动化。小图标还会彻底覆盖所在区域,使其难以去除。
做得好时,除非刻意寻找,否则几乎不会注意到。我在网上见过不少成功例子:一个网站使用小匕首符号,后来在其他网站的图片上看到同样的匕首,就很容易认出图片来自哪里。
文字水印
直接绘制文字也是简单的水印方式,上面的各种图内标签方法都可以使用。不过,最好采用两种颜色,避免文字在不同颜色背景上消失,因此应使用某种复合字体效果。
magick logo.jpg -font Arial -pointsize 20 \
-draw "gravity south \
fill black text 0,12 'Copyright' \
fill white text 1,11 'Copyright' " \
wmark_text_drawn.jpg

这种方式有效且可自动化,但文字太突出,作为水印显得过于醒目。
经过一些准备,可以生成透明背景的文字图像,使水印不那么突兀。原文的Font Masking以及Masking Images示例介绍了这里使用的字体蒙版与图像蒙版技术。
magick -size 300x50 xc:grey30 -font Arial -pointsize 20 -gravity center \
-draw "fill grey70 text 0,0 'Copyright'" \
stamp_fgnd.png
magick -size 300x50 xc:black -font Arial -pointsize 20 -gravity center \
-draw "fill white text 1,1 'Copyright' \
text 0,0 'Copyright' \
fill black text -1,-1 'Copyright'" \
-alpha off stamp_mask.png
magick composite -compose CopyOpacity stamp_mask.png stamp_fgnd.png stamp.png
magick mogrify -trim +repage stamp.png



有了水印字体,就能把它应用到图像上:
magick composite -gravity south -geometry +0+10 stamp.png logo.jpg \
wmark_text_stamped.jpg

现在水印不再像之前那样刺眼,使用的是灰度而非纯黑纯白,但无论背景如何仍然清晰可见。复合字体效果示例介绍了许多适用于水印的样式,能够避免喧宾夺主。
也可以将文字平铺到整张图。这里把上一条命令的输出直接输入下一条命令,构成管道,避免生成中间文件。
magick -size 140x80 xc:none -fill grey \
-gravity NorthWest -draw "text 10,10 'Copyright'" \
-gravity SouthEast -draw "text 5,15 'Copyright'" \
miff:- |\
magick composite -tile - logo.jpg wmark_text_tiled.jpg

这利用了照片类图像通常总有某些区域能显示平铺文字这一特点;示意图则未必如此。你可以把文字设为半透明,例如半透明灰色'#80808080'。下文更细致的水印方法也可以结合平铺使用。
图像水印
ImageMagick还提供了一些选项,用于在更大区域添加更细微的水印,这通常才是人们所说的图像水印。示例使用一张“水龙”图;它带有透明区域,用来检查IM是否正确处理透明度,避免出现难看的方形边界。
历史版本提示:在IM 6之前,-watermark与-dissolve对前景Alpha通道的处理存在问题,会产生奇怪的效果。
Watermark合成。 这个选项本来就是为水印设计的,虽然可用,但通常只适合纯黑白前景,而且可能产生难看的边缘伪影。
magick composite -watermark 30% -gravity south \
wmark_image.png logo.jpg wmark_watermark.jpg

详细说明见合成示例中的Watermark选项。
Dissolve。 我和其他用户发现溶解的效果更好。
magick composite -dissolve 25% -gravity south \
wmark_image.png logo.jpg wmark_dissolve.jpg

效果很好,但在纯黑或纯白像素上,水印的部分区域会消失:白叠白、黑叠黑都不可见。这两种颜色很常见,因此最好预处理水印,使其采用不同灰度而非纯黑白,参见下文“灰度化溶解”。
详细说明见合成示例中的Dissolve选项。
平铺。 不必只在一个位置放置水印,也可以平铺到整个背景。把gravity定位换成-tile即可;此时通常应让水印更淡一些。
magick composite -dissolve 15 -tile \
wmark_image.png logo.jpg wmark_tiled.jpg

灰度化Bumpmap。 要把bumpmap恰当地用于水印,需要先做灰度调整,把白与黑都映射到较浅的灰度范围,否则结果会非常强烈。
magick wmark_image.png -fill Gray91 -colorize 80 miff:- |\
magick composite -compose bumpmap -gravity south \
- logo.jpg wmark_bumpmap.jpg

Bumpmap作为水印的最大问题,是它只能让图像变暗。因此,对于很暗的图像,这种方式几乎没有用。
灰度化溶解。 同样的预处理也能改进dissolve:让水印的白色部分在白背景上稍微变暗,黑色部分在黑背景上稍微变亮。
magick wmark_image.png -fill grey50 -colorize 40 miff:- |\
magick composite -dissolve 30 -gravity south - logo.jpg wmark_dissolve_grey.jpg

我认为这种水印已经接近理想,满足所有要求。不过,还可以继续调整最终的溶解程度,使它更不显眼。
平铺灰度化溶解。 与上例完全相同,只是把水印平铺到整张图,并采用更低的溶解值。
magick wmark_image.png -fill grey50 -colorize 40 miff:- |\
magick composite -dissolve 15 -tile - logo.jpg wmark_dissolve_tile.jpg

magick composite不会处理动画这样的多图像文件,但其他方法可以。参见修改动画与添加标注中的示例。
用gravity定位图像和文字
理解gravity
从前面的例子可以看出,在大图中正确定位文字和图像非常重要,-gravity自然是其中的关键设置。
Tim Hunter曾在ImageMagick邮件列表中说:
在真正掌握gravity之前,它会把你逼疯。
对此,我完全赞同。
gravity只在以下情况生效:
-
涉及geometry类设置的操作,例如
-crop,以及Alpha合成中通过-geometry定位图像,包括多图像分层合成。 -
label:、caption:等文字图像生成器的文本对齐。 -
-annotate的文字定位与对齐。 -
-draw中的text与image方法,而且仅限这两种方法。
以下情况不使用-gravity:
-mosaic、-flatten和大多数-layers方法等图像列表或图层操作,尤其是GIF动画。这些操作通过较大虚拟画布上的图像偏移定位;偏移由-page、-repage元数据设置,始终相对于虚拟画布左上角。
这种定位方式不考虑gravity。
-draw的其他方法也不使用gravity定位,而且不太可能支持,因为IM为这些底层功能遵循的SVG草案没有定义gravity。
这意味着什么?首先,gravity确定-geometry所使用的原点,使文字和图像能相对背景的边、角或中心定位,而用户无须知道实际尺寸。这是它的主要作用。其次,它也定义叠加对象相对于该原点的水平与垂直对齐方式。
例如,East以右侧为参照并采用右对齐。严格说来,对齐方式应与gravity分开设置,虽然两者密切相关;但原文所述的IM把它们合为一个选项。作者希望将两者分离,并在未指定justification时回退到当前gravity设置。
如果你需要这项能力,可以通过邮件列表向Cristy提出。作者认为,需求足够多时,最终可能会实现。
用gravity定位图像
以下示例使用gravity把图像放到背景上:
magick composite label:Default rings.jpg gravity_default.jpg
magick composite label:Center -gravity center rings.jpg gravity_center.jpg
magick composite label:South -gravity south rings.jpg gravity_south.jpg
magick composite label:East -gravity east rings.jpg gravity_east.jpg
magick composite label:NorthEast -gravity northeast rings.jpg gravity_northeast.jpg





图像自身也按gravity对齐。例如,South把图像水平居中放在背景底部,但图像位于该锚点上方。这在旋转文字时更加重要。还要记住,-geometry给出的偏移是相对于gravity放置图像的位置。
偏移方向也会被调整为朝向图像内部。例如,-gravity South -geometry +10+10会把标签向背景内部移动:Y方向反转,X方向不变。
magick composite label:Default -geometry +10+10 \
rings.jpg gravity_default_pos.jpg
magick composite label:South -geometry +10+10 -gravity south \
rings.jpg gravity_south_pos.jpg
magick composite label:NorthEast -geometry +10+10 -gravity northeast \
rings.jpg gravity_northeast_pos.jpg



也可以把-gravity与-draw image结合,用一条命令绘制多个图像。
magick rings.jpg \
-gravity Center -draw "image Over 0,0 0,0 'castle.gif'" \
-gravity NorthEast -draw "image Bumpmap 0,0 0,0 'castle.gif'" \
-gravity SouthWest -draw "image Multiply 0,0 0,0 'castle.gif'" \
gravity_image.jpg

同样,也可以用-composite把图像叠加到背景上:
magick rings.jpg \
-gravity Center castle.gif -compose Over -composite \
-gravity NorthWest castle.gif -compose Bumpmap -composite \
-gravity SouthEast castle.gif -compose Multiply -composite \
gravity_image2.jpg

上述-compose选项详见Alpha合成。其他把多张图合并为一张图的方法,参见示例索引中的Layers of Multiple Images。
用gravity定位文字
图像如此,直接在图上绘制文字又如何?基本效果相同。gravity既影响-draw text的文字位置,也影响更适合文字绘制的-annotate。
magick rings.jpg -resize 120x120 \
-gravity northwest -annotate 0 'NorthWest' \
-gravity east -annotate 0 'East' \
-gravity center -annotate 0 'Center' \
-gravity south -annotate 0 'South' \
-gravity northeast -annotate 0 'NorthEast' \
gravity_text.jpg

图像定位与文字定位有一个重要差别:没有设置任何gravity时,字符串相对于字体基线绘制。
实际看一个例子:
magick rings.jpg -annotate 0 'String' gravity_text_none.jpg

仔细看,结果顶部只露出了String中g的一小段下伸部分,其余文字都画在背景之外。若把gravity设为NorthWest,文字就会像图像一样,相对于字体定义的包围框或底色框定位。
例如:
magick rings.jpg -gravity NorthWest -annotate 0 'String' gravity_text_nw.jpg

这种区分是为了让IM文字绘制与SVG等矢量格式兼容。矢量格式不使用gravity,因此启用gravity就表示让IM遵循图像放置规则,而不是基于字体基线与文字起点的矢量图形规则。
启用gravity之后,如果要关闭,可使用-gravity none或+gravity恢复默认的无gravity状态。
给文字加上偏移,并分别使用默认的None与NorthWest,就能看出两种方式的关系。
magick rings.jpg \
-gravity NorthWest -annotate +10+20 'NorthWest' \
-gravity None -annotate +10+20 'None' \
gravity_text_pos.jpg

这个例子看起来或许不明显,但两行文字可能重叠,尤其是g、p等字母的下伸部分。两者不是按完整字号间距分开,而只是按字体基线高度区分。最好不要混用这两种模式:要么使用gravity,要么不用。
沿左边缘居中放置文字
最后看如何把文字居中放在图像左边缘。旋转围绕文字的锚点进行,但锚点由旋转前的gravity确定,因此除非使用居中文字,否则效果往往不理想。
下面是常见的第一次尝试,希望让文字沿左边缘居中,结果却出人意料地失败:
magick rings.jpg \
-gravity West -annotate 90x90+10+0 'String' \
gravity_text_left_fail.jpg

文字确实位于左边缘,但只有文字起点,也就是旋转前的锚点,被放在中央。原因是IMv7的gravity也直接设置文字对齐,而对齐决定定位锚点。原文附有用PerlMagick编写的旋转文字gravity动画演示脚本im_annotation.pl。
作者还提供了相同程序的shell版本im_annotation与im_annotation_2,下载链接见原文。
一个技巧是先旋转整张图,再把文字放在南侧居中,最后转回去。虽然有些绕,但确实有效。
magick rings.jpg -rotate -90 \
-gravity South -annotate +0+2 'String' \
-rotate 90 gravity_text_left.jpg

另一种办法见下文“使用distort定位文字”。
使用draw定位文字
前面的例子用文字偏移相对于gravity点定位,但这不是唯一方法。还可以使用-draw translate:它能避开gravity对坐标偏移的影响,同时仍用gravity确定文字内部的对齐锚点。
以下示例加入了辅助线,辅助线不受gravity影响,用来显示相对图像中心应用的位置。先看文字偏移:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 70,70' \
-fill red -draw 'line 68,70 72,70 line 70,68 70,72' \
-fill blue -draw "text 20,20 'Offset'" \
text_offset.jpg

再看使用平移的文字:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 70,70' \
-fill red -draw 'line 68,70 72,70 line 70,68 70,72' \
-fill blue -draw "translate 20,20 text 0,0 'Translate'" \
text_translate.jpg

两者得到相同结果。但-draw text本来就要求提供偏移,因此命令行中更常直接使用偏移定位。然而,一旦加入文字旋转,两种方法会得到完全不同的结果,原因主要在于操作应用顺序。
绘制旋转文字
绘制文字有两种定位方式:文字偏移,或平移到最终位置。加入旋转后,两者效果很不一样。这涉及IM对绘图表面变换的处理。先看只设置偏移、不旋转的情况:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 70,70' \
-fill red -draw 'line 68,70 72,70 line 70,68 70,72' \
-fill blue -draw "text 20,20 'None'" \
rotate_none.jpg

旋转带偏移的文字:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 50,78' \
-fill red -draw 'line 48,78 52,78 line 50,76 50,80' \
-fill blue -draw "rotate 45 text 20,20 'Offset'" \
rotate_offset.jpg

对文字进行平移与旋转:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 70,70' \
-fill red -draw 'line 68,70 72,70 line 70,68 70,72' \
-fill blue -draw "translate 20,20 rotate 45 text 0,0 'Translate'" \
rotate_translate.jpg

这通常才是人们想要的效果,不过旋转偏移也能用于特殊效果。注意,绘图表面变换的实际作用顺序与书写顺序相反:先旋转,再平移。若交换rotate与translate的顺序,就会得到普通文字偏移旋转后的结果。
-annotate专门用于简化旋转文字定位:它直接要求IM以旋转方式绘制文字,而不是变换整个绘图表面。以下同时设置旋转与偏移:
magick -size 100x100 xc:white -gravity Center \
-fill cyan -draw 'line 50,50 70,70' \
-fill red -draw 'line 68,70 72,70 line 70,68 70,72' \
-fill blue -annotate 45x45+20+20 'Annotate' \
rotate_annotate.jpg

上述例子的根本问题是,IMv7的gravity不仅指背景中的位置,也指待绘制前景内部的锚点。原文将“Text Justification”描述为计划加入的独立但相关设置,用于前景对齐,而gravity负责背景定位。
使用distort定位文字
把SRT畸变与图层合成结合,是定位图像或文字图像的好方法。它提供完整的底层控制:既能指定放置位置,也能指定图像相对于该位置如何排列。首先生成透明背景的文字图像,再把它作为图层合成到背景上。
magick rings.jpg -background none label:'Some Text' \
-flatten layer_simple.jpg

文字直接出现在左上角。接下来使用适合图层的distort形式旋转它。注意用括号限制参与畸变的图像。
magick rings.jpg \( -background none label:'Some Text' \
+distort SRT 70 \
\) -flatten layer_rotate.jpg

文字的位置并没有改变!distort只是围绕文字中心这个锚点旋转,同时让该点在虚拟画布上的位置保持不变。因此,将变大后的图层展平合成时,文字图像中心这个旋转点仍未移动。下一步要移动锚点,需要使用几乎完整的SRT参数。
为了继续使用中心锚点,需要图像属性百分号转义,具体来说是FX百分号转义。下面把文字中心放在背景的+60+60位置。
magick rings.jpg \( -background none label:'Some Text' \
+distort SRT '%[fx:w/2],%[fx:h/2] 1 70 60,60' \
\) -flatten layer_translate.jpg

移动图层的另一种办法是-repage,尤其是带!标志的相对移动。图层天然以左上角为锚点。SRT畸变则不仅能按指定锚点平移,还能对源、目标锚点都使用浮点数亚像素坐标,从而摆脱许多其他操作的整数位置限制。
最后一个例子把旋转90度的文字放在左边缘。这次选取旋转前文字底部中央作为旋转与定位锚点,坐标为%[fx:w/2],%h。背景目标点也需要计算,即左边缘中央0,%[fx:h/2]。问题在于:畸变文字图像时,SRT无法访问背景图像。
解决办法是在背景图像可用时先计算位置,并保存到自定义设置中,再把它代入畸变参数。原文“Extract Information from Other Images”更深入地介绍了这项技巧。这里先计算背景位置,再畸变文字图像,把其锚点移到预先计算的位置。
magick rings.jpg -set option:my:left_edge '0,%[fx:h/2]' \
\( -background none label:'Some Text' \
+distort SRT '%[fx:w/2],%h 1 90 %[my:left_edge]' \
\) -flatten layer_on_left.jpg

my:可以换成任何不与已有前缀冲突的字符串。作者用它保存自己的设置,与IM编码器或特定选项的设置分开。百分号转义只是字符串替换,甚至可以据此构造整个Distort参数。但这些自定义设置在赋值后不能再直接参与算术运算,因此计算必须提前完成。
原文将让FX表达式使用百分号转义变量,列为IMv7中继续考虑的工作。
来源与版权
原文:Annotating Images — ImageMagick Examples,作者Anthony Thyssen。中文译文。版权归原作者及相关图片权利人所有。本文保留原文的版本说明、历史限制与计划性表述;示例按原文的UNIX/Bash环境书写。











暂无评论内容