⚠️ 这是一个非官方翻译网站,与 ImageMagick Studio LLC 无关。准确信息请参阅原文(https://usage.imagemagick.org/annotating/index.html)。

ImageMagick 示例 -- 为图像添加标注

ImageMagick 示例 前言与索引
标注图像 (标注图像的技巧)

本文介绍在大图像上用文字或其他图像进行标注的多种方法。标注既可以醒目而显眼,也可以含蓄而隐蔽。为图像添加标注的原因多种多样,但通常是出于以下目的:

  • 在图像上标记关于该图像内容的信息。
  • 指出或突出图像的某个方面。
  • 作为版权保护的一种形式,为图像添加版权信息或徽标。

ImageMagick 提供了很多方法来完成这些工作,但并非所有方法都能自己轻松地从手册中找到。本页试图介绍常用的方法。许多具体的手法在其他示例页面中有更详尽的讨论。如果你有兴趣为 GIF 动画添加标注或水印,建议你先通读本文,然后跳到 为 GIF 动画添加标注 作为起步。


标注图像

为图像添加标签的基本问题在于,无论图像是什么样子,都要让文字清晰可读。下面展示了许多方法,其中一些可以扩展以完成更复杂的任务。在这些示例中,我只使用 ImageMagick 的默认字体。建议你根据想要达到的效果,使用不同的字体和点数大小。

在图像下方(或上方)添加标签

连接标签并居中,从 IM v6.4.7-1 起已成为可能,因为 图像连接 现在会为对齐目的而遵循 gravity 设置。 |

  magick dragon.gif   -background Khaki  label:'Faerie Dragon' \
          -gravity Center -append    anno_label.jpg

[IM Output]
通过重新排列图像的顺序,你可以把标签连接到图像上方。 |

  magick dragon.gif   -background Orange  label:'Faerie Dragon' \
          +swap  -gravity Center -append    anno_label2.jpg

[IM Output]
Splice 与 Draw 是一种非常简单的方法:为图像增加额外空间,让我们得以把标签绘制/标注到图像中。 |

  magick dragon.gif \
          -gravity South   -background Plum   -splice 0x18 \
          -annotate +0+2 'Faerie Dragon'   anno_splice.gif

[IM Output]
同样的方法也可以用来在图像上方绘制标签,只需把 gravity 设置的 'South' 换成 'North' 即可。很简单! |

  magick dragon.gif \
          -gravity North   -background YellowGreen  -splice 0x18 \
          -annotate +0+2 'Faerie Dragon'   anno_splice2.gif

[IM Output]
除非作为更复杂的绘图功能的一部分,否则不再推荐使用 "-draw" 运算符直接在图像上绘制。有关其他文字绘制方法与技巧的更多细节,请参阅 文字的图像处理 一节。 用 Montage 添加标签 ImageMagick 的 montage 命令常被用户忽视,以为它只适合把整个目录的图像展示出来。其实它也提供了一种为图像添加标签的非常简单的手段。 |

  montage -label "Faerie Dragon"  dragon.gif \
          -geometry +0+0 -background Gold anno_montage.jpg

[IM Output]
montage 还能为你给图像添加边框及其他内容,因此这种标签形式在简单标注图像之外还有很多额外的可能性。 |

  montage -label "Faerie Dragon" dragon.gif \
          -font Candice -pointsize 15 \
          -frame 5  -geometry +0+0 anno_montage2.jpg

有关使用 montage 的更多信息,请参阅 Montage,图像阵列。 [IM Output]
用 Polaroid 添加标签 使用 montage 的一种替代方案,是使用 Polaroid 图像变换 来生成一幅相当花哨的带注释图像。 |

  magick -caption "Faerie Dragon" dragon.gif -gravity center \
           -background black +polaroid anno_polaroid.png

警告:此图像带有一定随机性地被扭曲(弯曲并旋转),因此除非禁用旋转,否则最终图像尺寸会有所不同。它还包含复杂的阴影与透明度效果,因此使用了 PNG 格式的图像来保存结果。 [IM Output]
你可以使用“超采样(Super Sampling)”技巧来减少旋转在结果图像中造成的“模糊”。相关示例请参阅 Polaroid 图像变换。

在图像本身之上添加标签……

直接在图片上写文字的问题在于,你无法确定所选颜色的文字是否清晰可读。绘制的目标图像可能是黑色、白色,也可能是五颜六色。 带轮廓的标签:最简单的方法是给字符串描一圈轮廓,把文字与图像分隔开。不过,由于 "-stroke" 字体设置会同时向内和向外为字体增加粗细,会削弱其效果(详见 Stroke 与 StrokeWidth)。为字体绘制背景轮廓更好的办法是把文字绘制两次。 |

  magick dragon.gif -gravity south \
          -stroke '#000C' -strokewidth 2 -annotate 0 'Faerie Dragon' \
          -stroke  none   -fill white    -annotate 0 'Faerie Dragon' \
          anno_outline.jpg

[IM Output]
如你所见,它是有效的,但效果不太好。相比默认的 'Times' 或 'Arial' 字体,使用较粗的字体效果会更好。此技巧的更多细节请参阅 粗描边合成字体。 绘制暗色框:让标注文字更醒目的更经典的方法,是把要添加文字的区域“调暗”,再用相反的颜色绘制文字。例如…… |

  magick dragon.gif \
          -fill '#0008' -draw 'rectangle 5,128,114,145' \
          -fill white   -annotate +10+141 'Faerie Dragon' \
          anno_dim_draw.jpg

[IM Output]
此方法效果很好,但如你所见,本例中我决定不使用 "-gravity" 来放置文字,因为调暗的矩形无法用 gravity 定位(这在将来可能会改变)。此外,其尺寸和位置可能取决于图像和最终文字尺寸,这可能需要一些额外的数学计算。 下色框(Undercolor Box):与其自己去绘制背景框,你可以让 ImageMagick 在框上使用“下色(undercolor)”。请参阅 文字下色框。文字的“下色”(如库 API 中所用),在命令行上可以用 "-undercolor" 选项来指定。 |

  magick dragon.gif  -fill white  -undercolor '#00000080'  -gravity South \
          -annotate +0+5 ' Faerie Dragon '     anno_undercolor.jpg

[IM Output]
如你所见,这比自己绘制暗色框简单得多,不过建议在绘制文字的开头和结尾各加一个额外的空格,把框稍微撑大一点。 合成标签:更理想的方案是预先准备好一幅文字图像,再把它作为图像叠加上去。这里我们在半透明背景上创建一个简单的标签,然后叠加它。 |

  magick -background '#00000080' -fill white label:'Faerie Dragon' miff:- |\
    magick composite -gravity south -geometry +0+3 \
              -   dragon.gif   anno_composite.jpg

[IM Output]
最后这种技巧有一些明显的优势。暗色框可以按标签大小来调整尺寸,并且可以用 "-gravity" 正确地定位它,而无需了解它所添加到的图像、或所用绘制字体的任何具体信息。
而且,你并不局限于只使用简单的暗色框。你可以准备非常复杂的字体图像,既可以预先准备好以便多次应用,也可以针对每幅图像即时生成。几乎所有的 合成字体效果 样式你都能使用,从而让你添加的文字非常出彩、显得专业。自动调整尺寸的标题(Caption):随着 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

[IM Output]
这种技巧非常适合把图像评注叠加到图像上,不过在命令行上这么做有其自身的问题,因为你创建的是一幅新图像,而不是在标注一幅旧图像。此问题的解决方案请参阅 用户自定义选项转义。 花哨的标签:作为最后一个示例,我将叠加一个用花哨的 柔和轮廓字体 创建的文字字符串,以确保它保持可见,同时又不为该标注创建矩形框。 |

  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

[IM Output]
如果你打算把同一个标签(比如一条版权信息)合成到大量图像上,那么最好单独生成标签,再用 "mogrify" 命令把该标签合成到每幅图像上。上面的 "-geometry +0-3" 偏移用于把合成叠加放得更靠近边缘,因为这幅图像柔和模糊的轮廓往往比所需的更大。
上述所有示例当然都应根据你自己的需求进行调整。不要像绵羊一样随大流。大胆尝试,让你自己的网站或程序拥有与众不同的独特风味。更重要的是,把它告诉 IM 社区。

FUTURE: select the black or white color based on the images relative
intensity.  This uses a number if very advanced techniques.

  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

Explanation:  Copy of image is resized to 1 pixel to find the images
average color.  This is then inverted and greyscaled using -fx, then
thresholded to either black or white, (as appropriate).
This single color pixel is now scaled to a larger tiling image, and
saved into a named memory register (mpr:).

The image is then used to set the fill tile, for the annotated text.
Their is however no simple method (at this time) to set the outline -stroke
color of the draw text to its inverse.

Other techniques are to use some text as a 'negate image' mask, or even a color
burn or color dodge compose operation, to distort the image with the text.

叠加图像 ImageMagick 中的 "magick composite" 命令和 "-composite" 图像运算符,提供了以各种方式把图像放到其他图像之上的主要手段。这些方法的细节在 Alpha 合成 示例页面中给出。不过,还有一些更高层的运算符同样利用了图像的 alpha 合成。它们包括 图像分层,以及本示例页面更靠下的 用 Gravity 定位图像。compose 的默认合成方法是 "Over",它只是把叠加图像叠加到背景图像上,并如你所料地处理透明度。背景图像还决定了结果的最终尺寸,无论叠加图像放在哪里(使用 "-geometry" 选项)。无论叠加图像位于中间、半出背景图像之外,还是远在天边,输出图像的尺寸都与背景图像相同。图像的 geometry 位置也会受 "-gravity" 影响,因此叠加图像的定位可以相对于九(9)个不同位置中的任意一个来定义。请参阅下面的 "定位图像与文字"。除了合成叠加的 "-geometry" 之外,单个图像还可以带有页面或画布信息(使用 "-page" 和 "-repage" 选项设置),这会影响图像的最终位置。不过,这种图像专有信息不受 "-gravity" 影响。那么进入示例……叠加大概是最常见的图像标注形式,而且做起来非常简单。这里我把一个 32x32 的城堡图标叠加到已准备好的按钮框中央。

  magick composite -gravity center  castle.gif  frame.gif  castle_button.gif

[IM Output] [IM Output] [IM Output]

你也可以精确地定位子图像。这里我们放置一只手,指出妖精龙的小爪子。

  magick composite -geometry +31+105  hand_point.gif dragon.gif \
            dragon_claw_pointed.jpg

[IM Output] [IM Output] [IM Output]

图像具体如何绘制到背景上,由 "-compose" 设置控制。上面所用的默认值是 "-compose over",它只是把图像叠加到背景上。所提供的其他大多数合成方法,除了在非常特定的情形下都不太好用,但这里介绍其中一些。有关此设置及其效果的更多细节,请参阅 Alpha 合成。Bumpmap 是一种颇为微妙的合成方法,它基本上按照叠加图像的亮度来调暗背景图像。叠加图像中凡是白色的部分都会被当作透明处理,而凡是黑色的部分则会在输出图像中变成黑色。这有点像把叠加图像当作墨水印章来使用,这是想象此操作的一种好方式。提示一下,用 bumpmap 叠加在浅色图像上效果最好。因此你可能需要在使用前先准备好 bumpmap 图像。这里我们在使用 "-compose bumpmap" 把龙图像画到纸卷图像上之前,先把它调整尺寸。

  magick composite \( dragon.gif -resize 50% \) scroll.gif \
            -compose bumpmap -gravity center   dragon_scroll.gif

[IM Output] [IM Output] [IM Output]

Bumpmap 也可以用来为图像设置整体效果,在这个例子中,我们把浅色的背景图案平铺到龙的上面。请记住,bumpmap 图像会被当作灰度图像处理,因此我们叠加图像中的任何颜色都会丢失。

  magick composite -compose bumpmap  -tile rings.jpg \
            dragon.gif  dragon_rings.jpg

[IM Output] [IM Output] [IM Output]

| 上面的 "-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

[IM Output] [IM Output] [IM Output]

旁注:上面生成 "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

[IM Output] [IM Output] [IM Output]

放置这幅小图像最好的思路,是把它添加得看起来真的像是原图的一部分。在上面的例子中,我添加了“眼睛”图像,让它看起来几乎像是巫师帽子的一部分(你也不希望它过度融入图像)。因此,这种技巧需要人工的处理,这使它无法完全自动化。这幅小图像也可能非常难以去除,因为它彻底破坏了所覆盖的那部分图像。而且如果做得好,除非专门去找,否则几乎察觉不到。我在网上很多地方见过它被用得很有效果。某个网站用了一个小小的匕首状符号。当我在其他网站找到的图像上发现同样的匕首符号时,从那个网站盗走的图像就变得非常明显了。 用文字添加水印 只是在图像上绘制文字,也是一种简单的加水印方式,上面 图像上的标签 的任何示例都可以用作一种水印。不过要做好这件事,你应该使用两种不同的颜色,以防文字在不同颜色的背景上绘制时消失。为此,应当使用某种 合成字体效果。 |

  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

这样效果很好并且可以自动化,但作为好水印来说太醒目了,因为它从图像中太过突出。 [IM Output]
但通过做一些准备,可以创建一幅透明背景的图像,使其不那么扎眼。有关生成水印文字所用步骤的细节,请参阅 字体遮罩。此外,图像遮罩 中的遮罩示例可能也有助于你的理解。

  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

[IM Output]

现在我们有了水印字体,可以把它应用到图像上…… |

  magick composite -gravity south -geometry +0+10 stamp.png  logo.jpg \
            wmark_text_stamped.jpg

如你所见,水印不像之前那么醒目,甚至使用了灰色的浓淡而非纯白和纯黑。即便如此,无论背景是什么,它仍然清晰可见。合成字体效果 页面详细介绍了许多可以这样使用、又不会压过被加水印图像的字体样式。 [IM Output]
你也可以把文字平铺到整幅图像上。这里我们还通过使用命令的“管道”,把一个命令的输出馈送给下一个,从而避免了对中间图像的需要。 |

  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'" 这样的半透明灰色)。在下面正规的水印技巧中,你也不妨记着这种平铺技巧。 [IM Output]

用图像添加水印

ImageMagick 还提供了若干选项,特别适合在更大范围内进行更微妙的水印处理。当你说给图像“加水印”时,通常更常指的就是这个。右边是一幅“水龙”图像,我将用它进行这些演示。它带有一些透明度,我用它来检查 IM 在透明度方面是否处理正确,避免结果出现难看的“方块”外观。 [IM Output]
在 IM 版本 6 之前,"-watermark" 和 "-dissolve" 选项在处理叠加图像的 alpha 通道(透明度)方面存在缺陷,会产生一些非常奇怪的效果。
--- ---
Watermark 合成本是为给图像加水印而设计的,虽然它有效,但往往只对纯白和纯黑的叠加图像有效,并会产生难看的边缘伪影。
  magick composite -watermark 30% -gravity south \
            wmark_image.png  logo.jpg    wmark_watermark.jpg

有关此选项的更详细信息,请参阅 Watermark 选项用法 页面。 [IM Output]
Dissolve 被我和其他人发现效果更好。 |

  magick composite -dissolve 25% -gravity south \
            wmark_image.png   logo.jpg  wmark_dissolve.jpg

这效果非常好,但在带有纯白和纯黑像素的图像上,水印的一部分会消失。也就是说,把白色溶入白色、黑色溶入黑色,在最终图像中都不会可见。由于这两种颜色非常常见,最好对水印做一些额外的预处理,让它使用各种灰色浓淡而非纯白和纯黑。(参见下面的“灰化 Dissolve”) [IM Output]
有关此选项的更详细信息,请参阅 Dissolve 选项用法 页面。 平铺(Tiled): 你也可以把水印平铺到整个背景图像上,而不只是加在一个位置。只需把你的 gravity 位置换成 "-tile" 即可。当然,那样的话你可能想让水印更不显眼。 |

  magick composite -dissolve 15 -tile \
            wmark_image.png   logo.jpg  wmark_tiled.jpg

[IM Output]
灰化 Bumpmap: 要把 bumpmap 恰当地用作水印,需要对图像做一些准备,使用 灰度调整 技巧把白色和黑色都变成较浅的灰色范围。如果不这么做,结果会非常非常醒目。 |

  magick wmark_image.png  -fill Gray91 -colorize 80  miff:- |\
  magick composite -compose bumpmap -gravity south \
            -  logo.jpg    wmark_bumpmap.jpg

[IM Output]
把 bumpmap 用作水印最大的问题在于,此操作只会调暗图像。因此这种技巧对非常暗的图像相当无用。 灰化 Dissolve: 同样的预处理技巧也可以配合 dissolve 方法使用,让水印图像的白色部分在白色背景上略微变暗,同样地,让水印在图像黑色部分上的黑色区域变亮。 |

  magick wmark_image.png  -fill grey50 -colorize 40  miff:- |\
  magick composite -dissolve 30 -gravity south -  logo.jpg wmark_dissolve_grey.jpg

[IM Output]
我要说,作为水印这几乎是理想的,满足了所有要求。不过我会进一步调整最终的 dissolve,让水印更不易察觉。 平铺的灰化 Dissolve: 这与上面完全相同,只是以更低的 dissolve 值平铺到图像上。 |

  magick wmark_image.png  -fill grey50 -colorize 40  miff:- |\
  magick composite -dissolve 15 -tile  -  logo.jpg wmark_dissolve_tile.jpg

[IM Output]
| "magick composite" 命令不知道如何处理动画之类的多图像文件。不过,其他方法确实可以让你做到这一点。有关标注和叠加多图像文件的示例,请参阅 修改动画、标注。


用 Gravity 定位图像与文字

关于“Gravity(重力)”的种种

如你在上面所见,能够在更大的图像中定位图像和文字,与其他任何事情同等重要。自然地,"-gravity" 设置是这方面最重要的方面之一。

在 ImageMagick 邮件列表上,Tim Hunter 如此宣称。
“ 在你掌握它的窍门之前,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" 并未定义。

这一切意味着什么呢?首先也是最重要的,它定义了 "-geometry" 用来相对于图像的边缘、侧边和中心定位叠加文字和图像的原点,而用户无需知道图像的实际尺寸。这是它的主要功能。其次,它定义了叠加对象(文字或图像)相对于所定义的 gravity 点的水平和垂直对齐。例如,在 'East' gravity 下,文字或图像会被放置在所定义点的右侧(右对齐)。从技术上讲,对齐应当是独立于 "-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

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

注意,图像的实际位置也会根据 "-gravity" 设置进行对齐。也就是说,"South" 的 gravity 会把图像居中于更大图像的底部,但在该 gravity 点之上。这一点稍后在文字旋转时会变得更重要。另一件要记住的事是,任何 "-geometry" 设置所指定的位置,都是相对于 gravity 放置图像的位置而言的。不仅如此,位置的方向也会被修改,使得位置方向朝内。例如 "-gravity South -geometry +10+10" 会把标签图像更往背景内部移动。也就是说,geometry 位置的 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

[IM Output] [IM Output] [IM Output]

你也可以把 "-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

[IM Output]
而且,你现在也可以使用 "-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

[IM Output]
有关上面所用 "-compose" 设置的更多细节,请参阅 Alpha 合成。有关把多幅图像叠加、合并并叠加到单幅图像中的其他方法,请参阅 IM 示例中的 多图像分层 一节。

使用 Gravity 定位文字

对图像来说这一切都很好,但直接在图像上绘制文字又如何呢?其实,与图像相同的基本效果同样适用。如上所述,无论是使用 "-draw" 的 'text' 方法,还是更好的 "-annotate" 文字绘制运算符,gravity 都会影响文字的定位。 |

  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

[IM Output]
定位图像和文字之间有一个非常重要的区别。如果你绘制一个文字字符串,而没有定义任何形式的 "-gravity",该字符串将相对于字体的“基线(baseline)”绘制。 例如,我们实际来做一下…… |

  magick rings.jpg -annotate 0 'String' gravity_text_none.jpg

[IM Output]
如果你仔细看,只会看到 'String' 中 'g' 那个小小的环状尾巴出现在结果图像的上边缘。字符串的其余部分被绘制到了背景图像之外。但如果你把 "-gravity" 设置为 'NorthWest',文字就会像图像一样被定位。也就是说,相对于字体所定义的 边界框或下色框。 例如…… |

  magick rings.jpg -gravity NorthWest -annotate 0 'String'  gravity_text_nw.jpg

[IM Output]
作出这种区分的原因,是为了确保 IM 的文字绘制与 "SVG" 等其他矢量绘图图像格式保持兼容。这些格式不使用 gravity,因此开启 gravity 就是告诉 IM 在绘制文字时遵循与图像放置相同的规则,而不是涉及字体“基线”和文字“起始”点的矢量图形规则。如果你开启了 gravity,之后又想关闭它,可以使用 "-gravity none" 或 "+gravity" 把它重置回默认的“无 gravity”设置。 让我们施加一个文字偏移,并把 "-gravity" 的默认 'None' 和 'NorthWest' 两个参数都绘制出来,好让你看到这两种形式关系有多么密切。 |

  magick rings.jpg \
          -gravity NorthWest -annotate +10+20 'NorthWest' \
          -gravity None      -annotate +10+20 'None' \
          gravity_text_pos.jpg

[IM Output]
虽然在这个例子里可能看不出来,但这两个字符串是可能重叠的,尤其是在 'g'、'p' 等字母的下伸部分方面。也就是说,这两个字符串并未按 'pointsize' 单位妥善分隔,而只是按字体的基线高度分隔。最好的做法是不要在你自己的图像处理中混用这两种模式。要么用 gravity,要么不用。选择在你。 使用 Gravity 在左边缘放置文字 作为最后一个示例,这里介绍如何真正沿图像左边缘居中进行标注。这里的问题是,当你旋转文字时,它会围绕文字的“手柄(handle)”旋转。遗憾的是,这个手柄是在文字旋转之前由 gravity 设置的,因此除非你把自己限制在“居中文字”上,否则效果不太好。 [IM Output] 例如,这是一次典型的“初次尝试”,试图把文字定位成沿图像左边缘的中央。当然,它相当出人意料地失败了! |

  magick rings.jpg \
          -gravity West -annotate 90x90+10+0 'String' \
          gravity_text_left_fail.jpg

如你所见,文字被放在了左边缘,但只是让起始点(旋转前“手柄”所在之处)居中而已。这个问题的原因在于,在 IMv7 中,"-gravity" 设置还被直接用来设置文字的“对齐”(它设置用于定位文字的“手柄”)。有一些用 PerlMagick API 编写的、关于 gravity 对旋转文字之影响的动画演示(下载 "**im_annotation.pl**")。我还创建了同一程序的 shell 脚本版本 "**im_annotation**" 和 "**im_annotation_2**"。 让这一切奏效的诀窍是:先把整幅图像旋转,然后使用 center south!这是个荒唐的解决办法,但它确实有效。 |

  magick rings.jpg -rotate -90 \
          -gravity South -annotate +0+2 'String' \
          -rotate 90  gravity_text_left.jpg

[IM Output]
另一种方法在下面的 使用 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

[IM Output]
带平移(translation)的文字…… |

  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

[IM Output]
如你所见,两者产生的实际结果相同。但由于 "-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

[IM Output]
带偏移地旋转文字…… |

  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

[IM Output]
带平移地旋转文字…… |

  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

[IM Output]
这实际上是大多数人想要的。不过偏移旋转对某些特殊效果也可能有用。注意这些 绘图表面变形 的执行顺序与给出的顺序是相反的。旋转先执行,平移后执行。如果你把 'rotate' 和 'translate' 方法调换,你会得到与普通“文字偏移”相同的结果,即一个旋转过的偏移。"-annotate" 运算符是专门设计来让定位旋转文字更容易的,它明确要求 IM 带旋转地绘制文字,而不是“进行表面变形”。带旋转和偏移的 annotate…… |

  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

[IM Output]
上述示例的问题在于,IMv7 的 "-gravity" 设置不仅指背景图像上的位置,也指要绘制的叠加图像中的位置。IMv7 将添加“文字对齐(Text Justification)”,它指的是叠加位置,作为独立于 gravity(背景位置)但与之相关的设置。

使用 Distort 定位文字

把 SRT 扭曲 与 图像分层 结合起来,是放置图像(或图像中的文字)的一种特别好的方法。它基本上让你对图像放在哪个点、以及图像相对于该点如何排布,都拥有完全的底层控制。这里先创建一张背景透明的“文字图像”,再简单地把它“分层”到背景图像上。 |

  magick rings.jpg -background none label:'Some Text' \
          -flatten  layer_simple.jpg

[IM Output]
如你所见,文字只是加在了图像的左上角。现在用扭曲(分层的做法)来旋转它——注意这里用括号来限定我们要扭曲的是哪张图像! |

  magick rings.jpg \( -background none label:'Some Text' \
             +distort SRT 70 \
          \) -flatten  layer_rotate.jpg

[IM Output]
注意,文字的位置并没有改变!发生的只是扭曲让文字绕中心点(即“手柄”)旋转,但相对于“虚拟画布”,该点并未移动。因此,当这张已经变大的图像经 展平 之后,它的旋转点“文字图像的中心”也没有移动。下一步是移动这个手柄,为此我们需要用上几乎全套的 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

[IM Output]
移动“图层图像”的另一种方法是使用 Repage 运算符,尤其是用 '!' 标志做相对移动。由于图层图像的性质,这里的“手柄”就是左上角。SRT 扭曲运算符 不仅能用指定的手柄平移图像,还能为这两个手柄都使用子像素(浮点)位置。也就是说,它可以按子像素的增量把文字扭曲到任意位置,而没有大多数其他操作都有的整数限制。最后一个示例是把旋转 90 度的文字放到左边缘。这一次,文字用来旋转和定位的手柄将位于旋转之前文字的底部中心,也就是算出来的位置 '%[fx:w/2],%h'。背景图像上的位置现在也必须算成左边缘的中心('0,%[fx:h/2]')。问题在于,SRT 扭曲运算符 在扭曲文字图像时无法访问背景图像。解决办法是在背景图像可用时先做这个位置计算,并把结果保存到某个“个人设置”中,随后再把它加入扭曲参数。这项技术在 从其他图像获取数据 中有更细致的讨论。结果如下。先计算背景图像上的位置,再扭曲文字图像,使其“手柄”也移动到那个预先算好的位置。 |

  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

[IM Output]
'my:' 这个字符串可以是任何不与已有前缀冲突的名字。也就是说,我用它来存放我自己的设置,与 ImageMagick 可能为 coder 或特定选项使用的其他设置区分开。用 'my:' 做前缀是个不错的选择。百分号转义纯粹按字符串替换来处理,实际上我们可以把整个 Distort 选项都生成为一个字符串。唯一的问题是,'my:' 设置一旦设好,就不能再对它做数学运算。所以任何数学计算都必须事先完成。这一点将在 IMv7 中加以考虑,好让 FX 表达式能使用 % 转义变量。