ImageMagick 示例 -
动画修改
- 索引
-
ImageMagick 示例前言和索引
-
动画的简单修改
-
动画 Alpha 合成
-
所有闪光...
-
调整动画大小
- 调整动画大小问题 (正在建设中)
- 调整动画大小技术 (正在建设中)
- 使用扁平化调整大小 - 一种通用解决方案
- 颜色表溢出
- 动画作为带填充的缩略图
-
合并多个动画
- 串行或按时间追加
- 并排追加(时间同步)
- 追加动画字体
- 拆分动画
- 合并时间不连续动画 (正在建设中)
动画的简单修改
首先是一个重要事项
不要直接将未完成处理的中间动画保存为 GIF,特别是尚未执行任何 半透明处理 或 颜色优化 的图像。如果您犯了保存为 GIF 的大错误,您将只是使生成的动画更糟糕,因为 IM 现在将执行自动 颜色量化,以减少存在的颜色数量以使图像适合有限的 GIF 格式。不仅如此,它还对每个帧完全独立地进行处理,从而产生了不同的颜色选择和抖动模式。也就是说,任何进一步的处理,尤其是任何 帧优化 都变得更加困难。对于调整大小的 GIF 动画,或您已添加多色叠加或底层的动画,这一点尤其重要,因为这会添加大量额外的颜色。如果您想逐步处理动画,可以使用 IM 内部格式 MIFF 作为临时文件格式,或者使用每个正在编辑的帧的单个 PNG 格式图像。只是不要在您确定不会出现颜色问题之前进行最终保存为 GIF。我再说一遍...
不要使用 GIF 作为中间文件格式,请使用 MIFF 或 PNG 图像。
添加注释- 在所有帧上添加版权声明
从 IM 版本 6.2.6 开始,您可以“-annotate
”动画,与 在图像顶部添加注释 中详细介绍的方式类似,只需这样做即可。例如,这里我们对 上一个处理过的动画 添加注释,该动画是在 动画基础 中创建的。
|
![]() |
-annotate
”将在图像的虚拟画布上定位文本,而不是相对于实际图像数据定位。因此,文本在每个帧上的位置对于动画图像都是正确的。然而,在 6.2.6 版之前,“-annotate
”与许多其他图像操作符一样,相对于实际图像定位信息和叠加层,并忽略子帧可能具有的任何页面或虚拟画布偏移量。需要注意的是,在没有首先 合并 动画的情况下,在动画上进行这样的绘制可能会导致一些不寻常的效果,因为动画存在优化方案(见下一组示例)。因此(如您将看到的),首先 合并 它以删除任何现有的帧和透明度优化是推荐的。 绘制- 修改合并的动画
现在,虽然“-annotate
”将文本相对于每个帧的虚拟画布放置,但许多其他图像操作不会。这包括所有“-draw
”操作,它们只绘制相对于实际图像的事物,完全忽略它在更大画布上可能具有的任何偏移量。例如,这里我们在 上一个处理过的动画 的左上角附近绘制一个花哨的绿色圆圈。
|
![]() |
-draw
”绘制了相对于“实际图像”的圆圈,而不是图像所在的更大虚拟(页面)画布。结果是,正如这种情况下的典型情况...一团糟。对此的简单解决方案是首先 合并 动画,然后再绘制,然后在之后重新优化 GIF 动画。有关详细信息,请参阅 优化动画。
|
![]() |
![]() ![]() |
虽然这种“合并-优化”技术适用于大多数涉及动画的操作,尤其是 IM 的优化器,但有些操作会对图像进行如此大的更改,例如主要颜色更改和阴影,以及半透明度,以至于生成的动画无法很好地优化。 例如,几乎所有“ -resize ”操作都可能产生一个动画,该动画在之后会非常糟糕地优化,因为发生了主要的颜色更改。有关此问题的解决方案,请参阅下面的 调整动画大小。 |
逐帧- 一次修改一帧
通过使用 IM 图像列表或序列操作符,您可以分别修改动画的每一帧。诀窍是将每一帧提取到括号中,修改它,然后用修改后的版本替换原始图像。例如,这里我们将文本作为版权水印添加到动画中,作为动画本身,使其更难以移除。为了不完全破坏动画,我还使用了半透明颜色。括号 的使用,以将“-annotate
”操作的影响限制为动画一帧的简单“克隆”。然后使用 交换 和 删除 操作符将修改后的图像返回到图像序列中的适当位置。![]() ![]() |
“-swap ”操作符中的单个数字用法是在 IM v6.3.4-3 中添加的。在此之前,您需要指定“-swap 3 ”作为“-swap -1,3 ”,才能使其正常工作。 |
在尝试修改动画之前先研究动画。
这会对最终结果产生很大影响。
这会对最终结果产生很大影响。
裁剪- 限制动画区域
IM 努力使“-crop
”图像操作相对于图像的虚拟画布正常工作,而不是相对于实际图像(IM 版本 6.1.1 及更高版本)。这反过来允许您做一些以前无法直接做到的事情。例如,裁剪 GIF 动画的图像,使其仍能按预期为所有动画工作。
|
![]() |
![]() ![]() |
不要使用“+repage ”从帧优化的 GIF 动画中删除裁剪偏移量。这样做也会删除将子帧定位在虚拟画布上的所需帧偏移量,而后续帧可能依赖这些偏移量才能正确动画。 |
-crop
”操作确实产生了警告消息...由于动画中一帧的裁剪区域错过了该帧使用的子帧叠加图像,导致该帧没有更新从动画中裁剪的区域。结果,该帧现在不包含任何真实图像!为了弥补,IM 不仅会生成警告消息,还会生成一个特殊的 '缺失图像' 作为动画中的占位符,以保持一切有序,并保留附加到该帧的任何“延迟”或“处置”方法。您可以保留该占位符,或者根据需要进行修复。在这种情况下,'缺失图像' 是动画按预期运行所必需的。但是,如果生成多个连续的缺失图像,您可能可以使用“-layers
”方法'RemoveDups
' 将它们合并成一个缺失的图像。但是,仍然建议谨慎操作并研究动画。(有关此的更详细示例,请参见下面的 分割动画。 裁剪画布- 动画的视窗裁剪
就像普通的裁剪一样,保留了原始图像的虚拟画布,动画的裁剪也是如此。这可能不是这种情况下的意图。因此,在 IM 版本 6.2.4-5 中,在 "-crop
" 参数中添加了一个特殊的标志 '!
'。此标志将导致裁剪不仅裁剪单个图像帧,还会将图像的页面或画布信息调整到相同区域。这被称为“视窗裁剪”,因为结果就像您通过一个大小和位置与裁剪参数相同的“窗口”或“视窗”来查看图像一样。虚拟画布的大小不仅设置为裁剪区域的大小,而且动画中每帧的偏移量也会进行调整以保持正确。(参见 带有画布/页面调整的视窗裁剪)。例如,让我们重复前面的裁剪,但使用 '!
' 标志裁剪画布信息...
|
![]() |
![]() ![]() |
'! ' 字符对某些 UNIX shell(如“csh ”)具有特殊意义,即使放置在引号内也必须用反斜杠转义。IM 将忽略反斜杠,在几何参数中,因此始终对其使用反斜杠并不会造成伤害。 |
-quiet
" 设置,要求 IM 不要给出有关 缺失图像 的警告消息,我们在之前的裁剪尝试中生成了该消息。建议在裁剪动画时始终使用此设置,因为警告实际上并不适用。请注意,视窗裁剪 还可以让您扩大画布区域,甚至重新定位画布内的所有内容。但是,这很危险,因为任何部分或完全超出裁剪区域的图像都将被剪裁,只显示出现在该区域内的图像部分。最后提醒一句。在使用“视窗裁剪”时,图像帧将在负方向上移动到“视窗”给出的偏移量。这看起来可能不合理,除非您记住裁剪运算符中的偏移量是视窗的位置,而不是图像本身的直接重新定位。 边界修剪- 自动画布大小校正
与之前的操作一样,修剪动画可能很棘手。如果动画包含一个简单的 清除帧动画,那么您可以通过计算动画中所有单个帧的最大边界来简单地修剪动画。从 IM v6.3.4-8 开始,您可以使用 'TrimBounds
' 图层方法非常轻松地做到这一点。对于 IM 早期版本的使用者,您仍然可以执行相同操作,但只能通过两步操作(这也执行其他不需要的处理)。为此,您将使用 图层合并 将动画的所有帧合并成单个图层,然后让 IM 报告该图层的尺寸和偏移量...现在您知道了所有帧的边界,您可以简单地将整个动画 视窗裁剪 到此尺寸。如果您还想从动画中修剪静态背景,那么最好的方法是在使用 图层合并 步骤之前,从 帧优化 动画中删除第一帧。然后,您可以使用返回的边界对原始动画进行 视窗裁剪。 重新定位帧
类似且相关的操作是“相对重新定位”运算符。这将向动画的所有单个子帧图层添加给定的偏移量,允许您相对于整个画布调整它们的位置。为了使 "-repage
" 操作相对,您还需要在它的参数中添加一个 '!
' 标志。例如,这里我们将动画的第二帧及以后的帧向下和向右移动 30 像素,将第一帧“背景”帧恢复到正常的 '+0+0
' 位置。
|
![]() |
|
|
![]() ![]() |
对于 Windows Internet Explorer 版本 8,上述动画将失败(仅显示前两帧)。每当帧试图在动画画布边界之外绘制图像时,就会发生这种情况。 |
如果您愿意,您也可以通过直接调整画布大小来扩展画布以匹配这些新边界...
|
![]() |
通过使用 边界修剪图层方法,您可以自动扩展动画边界,以包含现在被放置在“边界之外”的图像...
|
![]() |
![]() ![]() |
对于 GIF 动画,使用 "-repage " 将图像向左或向上移动,尤其是使用小画布,可能会失败。这种格式基本上无法使用负图像偏移量。为此,您最好也应用“视窗裁剪”,或使用“修剪边界”将所有偏移量移到更大的正画布中。任一方法都将保证所有图像帧的正偏移量。 PNG 和 MNG 格式可以处理负偏移量,但许多网络浏览器和其他程序可能无法理解此类偏移量,从而产生奇怪的效果。例如,“ Firefox ” 网络浏览器的一个版本在尝试显示具有负偏移量的 PNG 时,会生成非常大的图像。 |
反转动画- 使动画向后运行或循环
从 IM v6.3.3 开始,添加了 "-reverse
" 图像序列运算符(有关更多详细信息,请参见 反转运算符)。这允许您非常简单地反转合并的动画序列的顺序。例如,这里我使“手写 k”动画变成未绘制的!
|
![]() |
-loop
" 选项重新添加到上面,因为这需要附加到第一个图像,现在是最后一个图像!结果可能还需要一些时间调整,但如您所见,它现在“未绘制”字母!请确保在反转之前 "-coalesce
" 图像序列,因为任何现有的 帧优化 都依赖于图像顺序。最好先删除这些优化。 巡逻循环- 在两个端点之间来回循环
类似的技术是在动画的末尾添加反转顺序的帧,这样生成的动画就会在原始动画的第一帧和最后一帧之间循环。这有点像警卫在两个点之间巡逻,被称为“巡逻循环”。这里我使用图像 复制运算符(添加到 IM v6.6.8-7 中)来生成额外的帧(反转)。
|
![]() |
|
![]() |
颜色变形- 两个图像之间的动画变化
"-morph
" 运算符是一个特别有趣的运算符。它将获取图像列表,并在它们之间插入额外的帧,以便从一个图像到另一个图像进行柔和的颜色变化。但是,此运算符不是真正的“变形”,因为它只修改像素颜色,生成一系列 混合图像。真正的电影般的“变形”还涉及图像 变形,以将图像中对象的轮廓转换为另一个图像中的对象。例如,这里我使用 巡逻循环,使用颜色变形在玫瑰图像及其翻转形式之间生成额外的帧。
|
![]() |
|
![]() |
|
![]() |
transitions
" 和 "fxtransitions
" ImageMagick shell 脚本。示例页面包含脚本用来生成动画的基本算法。 调整大小变形- 动画大小变化
颜色变形运算符 实际上不仅可以在两个图像之间进行颜色混合,而且还会同时进行图像调整大小。例如,这里我对两个大小不同,甚至长宽比不同的图像使用 "-morph
"。
|
![]() |
|
![]() |
擦除- 从一个图像到另一个图像创建一个擦除
这实际上非常容易实现。只需叠加新图像的“薄片”。这些是使用简单的 平铺裁剪 直接生成的。例如,这里我们从一个图像擦除到其翻转版本,只是为了好玩,再擦除回去。
|
![]() |
|
![]() |
动画变形- 根据图像索引扭曲多个图像
许多运算符可以在其参数中使用 百分比转义符。这意味着你可以实际修改运算符,使其对正在处理的每个图像执行略微不同的操作。该方法涉及首先 复制图像,以创建 30 个(或你喜欢多少个)相同玫瑰图像的副本。然后,你使用 FX 百分比转义符 不同地修改每个图像,以根据图像索引“%[fx:t]
” 和列表中的图像数量“%[fx:n]
” 计算变形值。例如,这里我按计算量平移图像。
|
![]() |
|
![]() |
t
”)的值从“0
”到“n-1
”,因此公式“%[fx:t/n]
”的值将从“0.0
”到略小于“1.0
”的值。这非常适合上述重复或循环动画,但不适合生成从一个图像到新图像的过渡。在这种情况下,你希望最后一帧的最终帧具有“1.0
”的乘数,请使用公式“%[fx:t/(n-1)]
”。这只是现在可以使用图像索引在“%[fx:...]
”计算中轻松完成的操作的一个示例。想象一下,更复杂的扭曲可以实现什么。如果没有使用图像索引计算,上述操作将需要一个外部 shell 循环来单独生成每一帧,还需要一个单独的步骤来收集帧以形成最终动画。此类循环 shell 脚本的示例在 简单扭曲图像动画 中给出,因为这些运算符不允许在其参数中使用 百分比转义符。![]() ![]() |
在 IM v6.6.9-0 之前,涉及图像索引的 百分比转义符 和 FX 百分比转义符(如“%p ”、“%n ”、“%[fx:t] ” 和 “%[fx:n] ”)已损坏。通常,它们只会返回无用的值“0 ” 或“1 ”,而不是当前图像序列中实际的索引和图像数量。 |
附加标签- 向整个动画添加标签
与往常一样,有多种方法可以实际将标签附加到图像。例如,对于具有初始背景画布的动画,或仅将新颜色叠加到先前帧的动画,你可以只将标签附加到图像的第一帧。其他帧不会删除它。这里我们只是使用“-splice ”添加一些额外的空间,并使用“-annotate ”在其中添加一些文本。
|
![]() |
-coalesce
”到未优化的 合并动画。然后,我们可以在重新优化动画之前,将标签添加到动画的每个合并帧。
|
![]() |
-annotate
”将文本绘制到添加的额外空间中,你还可以使用合成方法(参见下一部分)将图像合成到添加的额外空间中。这样,你就可以准备一个更漂亮的标签,添加到动画中。当然,这样做可能会导致某些动画在之后无法很好地优化,尤其是 已清除帧动画,但这是添加标签的代价。这种动画的一种解决方案是在解释 已清除帧动画 的部分中显示的那样,添加一个包含标签的“初始背景画布”。另请注意,向动画添加标签会导致添加许多额外的颜色。这可能会超出 GIF 颜色限制,因此你可能需要准备好优化动画的颜色。一项非常困难的任务,如果可能,最好避免(请参见 颜色优化)。这对任何动画的任何通用修改都是一个问题。 删除透明度- 添加纯色背景
你在网上找到的大量动画都有透明背景。这些非常有用,因为你可以将它们放在网页上,而无需担心网页上可能存在的任何背景图案。但是,在处理动画时,尤其是在应用其他图像运算符(如“-resize
” 和 “-blur
”)时,这种动画会遇到问题。通常的解决方案是从图像中 删除透明度,通常是通过某种方式将它们叠加到特定颜色上,例如用作网页背景的特定颜色。
![[IM Output]](../images/script_k.gif)
LimeGreen
”背景颜色上。我们可以使用“-flatten
”来实现这一点,因为我们只将其应用于单个图像,而不是整个动画。
|
![]() |
-coalesce
”,然后使用 Alpha Remove 运算符 从所有帧中实际 删除透明度。这次,让我们使用“Tomato
”背景颜色来实现这一点。
|
![]() |
背景
”处置设置都将通过 帧优化 过程转换为“无
” 或 “前一个
”,因为透明度不再是一个问题。![]() ![]() |
Alpha Remove 已添加到 IM v6.7.5 中。如果你的 IM 版本较旧,你需要使用其他方法,例如使用 边界运算符 的副作用。有关此方法和其他方法的详细信息,请参见 删除透明度。 |
多图像 Alpha 合成
下一级动画处理需要能够将单个静态图像合成到现有动画的上面或下面。也就是说,一般的 Alpha 合成。当两组独立的图像合并时,情况会变得更加复杂。在 IM v6.3.3-7 之前,多列表合成只能使用专门设计的 API 脚本,或保存和合并动画各个帧的 shell 脚本。这两种都不是很好的技术,但这确实是当时所有能够实现的方法。也就是说,现在已经改变了。绘制图像- 将图像绘制到图像列表上
“-draw
”运算符能够将源 图像合成到图像列表的顶部。它也是在 IM v6.3.3-7 之前,你可以在“mogrify
” 命令中使用的唯一多图像 Alpha 合成方法,或者可以针对多个图像使用该方法。这种 Alpha 合成技术之所以如此重要,是因为它允许你将图像指定为当前图像列表的单独参数。也就是说,在“-draw
” 的引号括起来的 Magick 矢量图形 语言中。由于其历史重要性,我将详细介绍其用法,尤其是对于仍然使用旧版本 IM 的用户。例如,这里我将玫瑰图像叠加到整个动画之上。
|
![]() |
Dst_Over
”合成方法,你还可以将图像“在下面”放置到动画作为静态背景。例如,这里我们“在下面”放置一个“netscape:
”内置图像,不过它可以是任何外部图像文件...
|
![]() |
|
![]() |
|
![]() |
图层合成- 图像列表的 Alpha 合成
在 IM v6.3.3-7 中,"-layers
" 方法添加了 'Composite
',允许将两个完全独立的图像集合成在一起。 (有关简要总结,请参阅 图像分层,图层合成)要在命令行上执行此操作,需要一个特殊的 'null:
' 标记图像来定义第一个目标图像列表的结束位置以及叠加的源图像列表的开始位置。但这只是此方法唯一的真正复杂之处。所以让我们尝试通过从一组图像创建一组阴影,然后将原始图像叠加在这些阴影图像上...
|
![]() ![]() ![]() |
null:
' 图像分隔符,以便 ImageMagick 知道一个序列何时结束以及下一个序列何时开始。此图像分隔符将被接下来的所有重要的 "-layer composite
" 操作自动删除。其他 API 应该能够使用单独的图像“魔杖”,而不是使用具有特殊分隔符的单个序列。然后执行图层合成,就好像这两个动画或图像序列只是一个简单的单个图像,而不是多个图像的序列。每对图像(一个目标图像和一个源图像)都被合成在一起,以生成合并(合成)的图像序列。最终结果是,我们已将阴影添加到原始动画序列中,该序列已准备好进行 GIF 优化,或者直接使用。现在你可以在单个命令中执行上述所有步骤。但是你不能仅仅使用 "
-clone
" 来创建原始序列的副本,因为我们实际上不知道(也不想)序列中有多少个图像。相反,你可以使用 "MPR:内存程序寄存器 来保存整个图像列表。这有点像对当前内存中的整个图像序列进行快照,然后在稍后再次读入它。结果是像这样的命令,尽管我使用了不同颜色的背景。
|
![]() |
-geometry
" 合成偏移量来修复这个问题。基本上,这些例子表明 图层合成操作符 实际上理解了各个虚拟画布偏移量("-page
")设置并将处理它们,就像图层扁平化 或更好的 图层合并 操作符处理它们一样。但是 图层合成操作符 也理解合成几何图形("-geometry
")偏移量(默认值为零)的使用,以控制整个叠加图像序列的整体放置。它甚至理解 "-gravity
" 对该全局偏移量的影响。例如.. 让我们将原始的 'K' 动画叠加在生成的阴影动画的“南部”...
|
![]() |
![]() ![]() |
"-geometry " 的调整大小功能并非严格意义上的合成操作的一部分,它只会调整当前图像序列的最后一个图像的大小。因此,如果与多图像图层合成 一起使用,它将不会按预期工作。有关详细信息,请参阅 调整大小几何图形。 |
真的很简单。我说简单了吗?
图层合成详细信息......如你上面所见,"
-layers Composite
" 的命令行版本使用当前图像列表中找到的第一个 'null:
' 图像作为标记来分隔这两个列表。这两个图像列表被分隔开,并且在两个列表被Alpha 合成 到一起(一次两个图像)之前,'null:
' 被丢弃。只有从特殊的 'null:
' 图像源生成的图像才能用作标记,如果找不到,则会报告错误。目前你无法从管道中读取此 'null:
' 标记图像(至少现在还不行),只能在需要时生成它。图层合成也比简单的两个图像Alpha 合成 复杂得多,因为图像列表的虚拟画布也被考虑在内。通常,Alpha 合成会忽略任何虚拟画布大小和偏移量以进行定位,只使用图像的实际大小。这种特殊的图层方法使用虚拟画布信息进行几何图形定位,以便对齐两个图像序列。为此,任何子帧的虚拟画布偏移量也会添加到正常调整的 "-gravity
"、"-geometry
" 合成偏移量中,以计算出图像叠加的位置。只有每个列表的第一个图像的虚拟 "-page
" 画布大小用于计算 "-gravity
" 对 "-geometry
" 合成偏移量的调整。后续图像的画布大小将被忽略,只将单个虚拟 "-page
" 偏移量添加到计算的 "-geometry
" 偏移量中。换句话说,"-layers Composite
" 是为“图层”或“动画”的 Alpha 合成而设计的,以及此类图像列表的特殊要求。警告...但是,你仍然需要注意你要叠加的图像列表。例如,如果目标列表图像不够大,或者定位不正确以包含叠加的源图像,则叠加的图像将被裁剪,或者完全错过目标图像。出于这个原因,在叠加较小的源图像之前,最好将目标图像合并 到完整的画布大小。例如,请参阅下面的逐尺寸动画追加 示例,其中画布大小需要扩展以提供追加图像的空间。此外,如果源图像列表是 GIF 动画,那么你可能需要确保子帧中没有诸如:压缩优化 和花哨的帧优化;否则你可能会遇到问题。另一方面,清除帧动画 或合并动画 可以直接 'Composite
' 而不出现任何问题。请记住,图层合成 不会理解图像中可能存在的任何现有的GIF 处置方法,尽管它会保留目标 GIF 动画元数据,例如:处置方法、帧延迟 和迭代循环限制。下面给出的特殊情况是对此的唯一例外。 单图像合成- 使用单个图像合成图像
通常,两个长度相等的图像列表被合成在一起,一次合成一对图像,直到其中一个图像列表用完。不会重复任何图像列表。合成将停止。你只留下具有附加合成的原始目标图像列表。'null:
' 分隔符图像和所有源图像将从当前图像列表中删除。![]() ![]() |
此图层方法的 API 接口应该允许你生成两个单独的图像列表,并且你将负责删除用于生成结果图像列表的两个输入图像列表。 'null: ' 分隔符应该不需要。 |
静态背景- 在更大的背景上合成
例如,使用这种特殊的单图像图层合成 方法,我们可以将动画合成在静态背景上...
|
![]() |
-gravity
”,因此图像被正确居中,无需您自己进行计算。但是,如果源帧包含偏移量,这些偏移量也会被添加到定义的重力位置中,以便所有子帧的相对位置保持正确。请注意,由于动画“script_k.gif
”实际上是一种叠加动画,因此存在将静态背景添加到动画中的替代方法。有关示例,请参见上面关于移除透明度的部分(到纯色,但可以是任何图像)。对于更简单的清除帧动画也是如此。在这种情况下,您甚至不需要先合并动画,而是可以直接将其合成到背景图像上。但是,您可能需要“-set
”之后使用的“dispose
”方法,或者更好的是优化完全合并的动画。但是,任何其他类型的优化动画都需要“-coalesce
”操作,以及所有动画帧的完整合成。因此,最好使用上述方法,以确保所有 GIF 动画都得到正确处理。所有闪光的东西...
闪光动画
以上图层合成方法使生成简单的动画(如闪光)变得容易得多。首先,我们需要一些足够大的闪光来覆盖要处理的图像。在这里,我将从一些随机斑点图像生成一个三图像闪光动画。首先,这是一个在纯透明度上的原始黑白闪光,通过将三个颜色通道分离成黑白通道图像,生成 3 帧闪光。它基本上是生成任何其他类型闪光的原始起点。“30%
”阈值控制每帧的“点”数量。
|
![]() |
屏幕
” alpha 合成叠加它,以仅使某些颜色变亮,从而生成特定颜色的闪光。我使用边框扁平化方法(上面)。只是一个纯色...
|
![]() |
|
![]() |
magick -size 100x100 -fill white -background none -font Candice \ -gravity center -pointsize 90 label:A glitter_mask_trans.gif magick glitter_plasma.gif null: glitter_mask_trans.gif -alpha set \ -compose DstIn -layers composite glitter_masked_trans.gif |
![[IM Output]](glitter_mask_trans.gif)

![[IM Output]](glitter_masked_trans.gif)
magick -size 100x100 -fill white -background black -font Candice \ -gravity center -pointsize 90 label:A glitter_mask.gif magick glitter_plasma.gif null: glitter_mask.gif -alpha off \ -compose CopyOpacity -layers composite glitter_masked.gif |
![[IM Output]](glitter_mask.gif)

![[IM Output]](glitter_masked.gif)
|
![]() |
![]() ![]() |
虽然我可能在上面使用了 GIF 格式图像来让我能够使用 magick 显示过程的各个步骤,但在实践中,您要么将所有步骤组合成一个命令,要么使用更好的中间图像文件格式,例如 MIFF。也就是说,这样做是为了避免 GIF 格式的固有问题,直到我们完成。 |
闪光图块- '图像中的洞' 下层
如上所述,WWW 上有很多预先准备好的动画闪光图块图像(搜索“闪光图块”)。一个来源是IM Studio用户,scri8e及其网站Moons Stars。但是要注意,我发现大多数闪光图块看起来非常糟糕,或者速度太快。
以下使用了一种巧妙的技术来平铺多图像闪光图块。但是,您仍然需要提供一个大于原始图像的大小,以确保您能够完全覆盖它。
|
![]() |
现在,让我们通过将上面的平铺闪光放在“有孔”图像下面,为我们的巫师穿上新衣服。
|
![]() |
当然,您可以将所有这些步骤都放在一个命令中。在这里,我将孔的生成限制在巫师的斗篷上,斗篷有两个单独的特定部分。
|
![]() |
![]() ![]() |
使用通用扭曲运算符及其特殊的“viewport ”选项(添加到 IM 6.3.6-0 中),还让您有机会以其他特殊方式修改扭曲模式。例如,赋予它“透视”外观或将模式旋转到非矩形角度。这样做可以增强平铺,使其看起来不像那么均匀。有关示例,请参见仿射平铺。 |
闪光- 叠加大部分透明的闪光
前面两种闪光动画技术的重大问题是,它是一种全有或全无的替换类型。您不能使用图像的原始阴影或背景。此外,闪光完全局限于被遮罩的区域。它不能扩展到所涉及区域的边界之外。因此,某些小区域,例如前面示例中的巫师“帽子”,不能很好地处理闪光。闪光不同,因为添加的动画大部分是透明的。因此,原始图像仍然可以透过来。这种动画通常以两种方式之一添加到图像中。要么动画叠加本身是透明的,要么它以黑色背景和白色“火花”的形式存在,图像应该在这些“火花”处变亮。

添加眩光和星星动画
闪光由单个亮度点组成,闪光可以叠加图像的某些区域,而眩光通常是单独添加的。“眩光”基本上是一个闪烁以在短时间内覆盖较大区域的点。“星星”类似,只是覆盖更像亮度的“光线”。这些通常从特定点“播种”,但结果往往会至少在短暂的时间内扩展到播种区域之外。例如,限制在特定区域的眩光看起来非常非常愚蠢和不自然。眩光更难的部分是找到好的“种子”点和适当的时间安排多个眩光。

Final example I want to create... A 'sparkle' the travels up the wizards wand, then flares, and dissolves into a number of small sparkle flares over an area. Then the sequence repeats.
调整动画大小
调整动画大小的问题
调整 GIF 动画大小的最大问题是,“-resize
”运算符专为使最终图像尽可能接近理想状态(在调整大小后)而设计。它通过合并和生成图像中的大量附加颜色来做到这一点,使其看起来更好。最终图像远非适合保存到有限的 GIF 文件格式。由于 GIF 颜色表有限,这会导致调整大小的图像中发生严重的颜色减少。对于单个 GIF 图像,情况并非那么糟糕,但对于 GIF 动画,减少颜色集的默认错误校正抖动会导致问题,表现为帧之间的“抖动噪声”,进而导致最终文件大小的帧优化较差。当还使用透明颜色时,情况会更糟,而这在网页使用的典型 GIF 动画中是一种常见做法。透明度也常用于压缩优化技术,用于本来不需要压缩的动画。发生的事情是,“-resize
”会在叠加图像中生成半透明像素。然后,当图像被保存回 GIF 文件格式时,这些像素会被转换为完全透明或完全不透明,两者都会在最终动画中产生重大颜色失真。如果使用了任何形式的优化... 帧、透明度或 LZW ... 那么透明度效果基本上会导致灾难性的调整大小的 GIF 动画。这就是事实,杰克!所以你必须忍受它。即使您通过使用“-sample
”来避免使用“-resize
”,您仍然会遇到重大问题,除非您先“-coalesce
”动画。 调整大小动画技巧
如上所示,调整 GIF 动画大小存在严重问题,这些问题都不容易解决。解决方法通常还取决于最初调整大小的图像类型,无论是卡通图像还是现实世界的视频图像。以下是我知道的或已贡献的方法...避免调整大小
如果可能,请勿调整大小。例如,您可以裁剪画布或视窗动画,将其修剪到适合所需空间的大小。或者,您可以在一开始就生成正确大小的 GIF 动画。这两种技巧通常都不是最佳选择,但如果可以,请考虑使用它们,因为它们可以为您节省很多麻烦和精力。直接调整大小
如前所述,直接使用“-resize
”会出现问题,无论是每帧的颜色数量还是半透明颜色。例如,这种情况非常糟糕...
|
![]() ![]() ![]() |
-resize
”将完全独立地调整每个帧图像的大小。也就是说,上面调整的是实际的帧图像,而不是动画的虚拟画布大小。实际上,我很惊讶生成的动画不是“疯狂”得多,而只是显示了一个空白区域。这让我们回到了调整动画大小的第一个要点。首先确保所有帧都完全定义,并且已删除所有优化。换句话说,在尝试调整动画大小之前,合并动画。例如...
|
![]() ![]() ![]() |
-resize
”运算符生成的。动画对象内部的颜色也会合并以产生新的颜色,但这通常不像边缘锯齿那样糟糕。 使用 Flatten 调整大小,通用解决方案。
生成 GIF 缩略图时,最好的做法是完全避免透明度问题。也就是说,在调整动画大小之前或之后扁平化动画。这样一来,您就不会在调整大小的图像中丢失边缘的“抗锯齿”。事实上,我发现大多数优秀的 GIF 动画网站在生成 GIF 动画缩略图时正是这样做的。当然,缩略图的使用将仅限于特定颜色的背景,通常是“白色”,但有时是“黑色”或“银色”(网页灰色),尽管现在这种方法不太常见。例如,这里我在适合此网页的背景颜色上创建了一个较小的缩略图。
|
![]() ![]() ![]() |
颜色表溢出
最大的问题(正如我在本节开头提到的)是图像中生成了大量额外的颜色,尤其是在线条附近以及相邻颜色区域的边缘。您还会在图像边缘周围获得半透明颜色的调整大小光晕。这反过来又会扩大简单最小颜色动画所需的色表大小,这反过来又意味着调整大小的简单动画保存时会产生更大的文件大小。更糟糕的是,调整大小动画中的每一帧都可能生成一组不同的颜色,这会进一步增大“缩略图”动画的文件大小。还有一个问题是,在颜色量化之后,您可能不再拥有与原始动画相同的特定颜色(请参阅量化不会保留颜色)。也就是说,您可能不会有一个纯粹的白色区域,而是会获得一个偏白色区域。使用 Sample 调整大小
为了避免在调整大小操作时生成额外的颜色,最简单的方法是“-sample
”动画,而不是调整其大小。这将保留动画中的当前颜色,并允许您轻松地以新大小重新优化动画。
|
![]() ![]() ![]() |
使用 Liquid Resize 调整大小
与使用上面Sample方法类似,还可以使用Liquid Rescale,也称为缝合雕刻。这也会从相关的图像中删除或添加整个像素,但会尝试以尽可能保留图像复杂性的方式进行操作。查看上面的链接,了解如何使用它来生成更美观的调整大小图像。不幸的是,目前无法在通用动画图像上使用此方法,因为它不了解图像的复杂性,并且我们目前无法提取重新缩放方法以以一致的方式将其应用于动画的每一帧。希望将来这一点会有所改变。调整大小并恢复颜色
对动画进行采样只会导致删除像素行和列,以及可能删除细线和其他重要细节。但是,使用“-resize
”将像素合并在一起会为 GIF 格式生成太多新的颜色。因此,显而易见的解决方案是执行“-resize
”,然后使用原始动画的颜色来恢复调整大小的动画颜色,方法是使用色图。FUTURE: example with original color table restored这具有不生成局部色表的额外优点。但是,结果在关闭抖动的情况下可能会更好,以避免任何“抖动噪声”。对于具有大型平滑彩色区域的卡通图像尤其如此。
FUTURE: non dithered color table restored example
完全颜色优化
如果您不喜欢糟糕的采样缩略图,那么您将面临对调整大小的 GIF 动画进行完整的颜色优化,以便确定要保留哪些“新”颜色。但是,对于大多数动画来说,这通常并不糟糕,但对于更复杂的动画来说,可能是一项艰巨的任务,例如在将视频转换为 GIF 动画时。也就是说,如果您处理的是卡通动画,那么现在您将拥有严重抗锯齿的线条和边缘。对于涉及透明背景的动画,您还必须正确处理动画边缘周围的半透明像素,这也是抗锯齿功能导致的。有关如何处理此问题的多种方法,请参阅有关GIF 布尔透明度的部分。大型调整大小减少
当您计划将大型动画调整为更小的动画时,您会面临动画重要部分消失的问题。这实际上是静态图像和动画都会遇到的问题。有关此问题的任何已知解决方案,请参阅调整大小线条图。欢迎任何进一步的建议、想法或技巧。
合并多个动画
我之前说过,但在合并动画时这一点变得尤为重要...
尽可能了解您正在处理的动画!
“gif2anim
”脚本非常适合此目的。它的姊妹脚本“anim2gif
”也常用于此,以使用原始设置重新创建动画。(有关脚本的基本用法,请参阅动画列表信息)。如果没有对动画工作原理的了解,就几乎不可能以各种方式合并它们。可以开发程序(这些示例的最终目标)来执行此操作。但是,此类程序通常非常复杂,并且可能会产生意想不到的结果。因此,您仍然应该遵循这些示例,因为它们将使您深入了解如何处理和合并动画。 串行或按时间追加
将两个 GIF 动画附加在一起,使一个序列在时间上遵循另一个序列,在 IM 中很简单。您基本上只需在命令行中列出它们,它们就会相互遵循。但这可能不像看起来那样容易。例如,在搜索网络后,我发现(嗯,窃取并为本示例进行了大量修改)几个字母被绘制的动画。现在我想将这些图像连接起来,这样当一个动画完成时,下一个动画就会开始,就像有人正在写“OK
”这个词一样。以下是字母、动画序列以及这两个动画内部细节的详细信息。
|
|||||
|
|
![]() |
|||
![]() |
k
”动画在动画序列的中间有一个小的延迟。此延迟表示此动画中第一次笔划的结束和第二次笔划的开始。此延迟也需要保留,这意味着我们不能简单地将动画中的所有时间序列更改为一个常数值。上面没有显示的是,两个动画的第一帧实际上是空白画布。我们可能希望在第二个动画中丢弃该画布,因为它是一种无用的浪费时间,尽管它应该保留在第一个动画中,作为开始延迟。现在我们已经检查了这两个动画,让我们尝试将它们连接在一起,使一个在时间上遵循另一个。时间附加动画实际上是一个非常简单的操作,只需在命令行中附加两个动画图像即可。因此,让我们试一试...
|
![]() |
o
'动画比第二个'k
'动画更薄(40像素),而第二个'k
'动画更宽(53像素),因此最终'k
'字母的最后一点被较小的框架画布大小裁剪掉了。第二个动画的位置可以通过使用相对重新分页来移动,如上所示。这种重新定位方法将保留该动画中可能存在的任何现有偏移量,只是将它们全部作为单个相关组移动。在本例中,几乎所有帧都有一个现有的偏移量,因为这是一个高度优化的动画。为了适应这种偏移位置并避免裁剪第二个动画,我们还需要扩大整个动画的画布大小。在读取第一个动画或帧之前更改画布大小将扩大动画运行的画布区域,并防止“K”被裁剪。
|
![]() |
O
'动画最后一帧的更短延迟。只要足够大,看起来就像看不见的艺术家正在重新定位钢笔。为此,我们复制第一个动画的最后一帧,然后使用“-set
”运算符更改该帧的延迟。然后,我们通过删除原始的未修改图像将该帧重新添加到图像序列中。另外,由于我们现在在字母绘制之间设置了良好的延迟,因此第二个动画中的初始空白画布(仅代表初始开始延迟)现在是多余的,所以我们可以直接删除该帧,不会有任何问题。如果此帧实际上包含图像的一部分,那么我们可能需要调整其延迟,而不是删除它。
|
![]() |
并排追加(时间同步)
假设你想要将两个动画并排追加,但同时让动画的两部分都进行动画。这并不容易,因为你需要将两个动画中的每对帧追加(或合成在一起),这样动画也能一起工作。这样做真正的难题在于,IM 命令行只适用于单个图像序列。它没有 API 的奢华,你可以在其中保存两个独立的图像序列,循环遍历并将其追加到第三个序列中。我能想到三种基本的技术来进行这种追加。然而,在我们开始之前,你应该首先研究这两个动画,以检查时间序列和其他动画细节。“gif2anim
”脚本对此很有用,生成的“.anim
”文件以后会很有用。
|
|||||
|
|
![]() |
|||
![]() |
![[left]](../images/bag_right.gif)
![[right]](../images/bag_left.gif)
追加单独的文件
最简单的方法是将两个动画合并并将其分成单独的图像文件,每个文件一个帧。然后可以根据需要将这些单独的图像追加在一起(或以其他方式修改帧)。完成之后,可以使用新帧重新构建动画。但是,这需要你保存大量关于动画的额外信息,这些信息在处理过程中很容易丢失。
|
![]() |
gif2anim
”脚本的强大功能,它是“anim2gif
”脚本的逆过程,用于分离和保存动画元数据,然后重新构建 GIF 动画。基本上,它可以让你保留动画的原始时序,而无需将它们直接编码到脚本中。最终图像还需要重新优化,不过在本例中,你会获得很少的优化,因为在整个动画中,每个帧之间都会同时发生很多事情。分层合成
更好的技术是使用多图像列表分层合成来覆盖动画。这只需要扩大一组图像,然后覆盖另一组图像以将它们连接在一起。实际上,这就是普通“-append
”运算符在内部所做的,因此它并没有太大区别。这里我只告诉 IM 要制作画布的大小,然后使用“-coalesce
”将其填满。然后,我用适当的偏移量覆盖另一个合并的动画。
|
![]() |
-gravity East
”将其放置在预先准备的画布的最右侧,以避免需要偏移量。
|
![]() |
双重追加,追加 - 或追加动画字体
在结束动画追加之前,我还要向你展示另一种技术。这种技术可以同时追加多个动画,但代价是丢失所有存在的时序信息。通常(但并非总是如此),这些时序的丢失并不算什么大损失。基本上,我们将每个动画的所有帧垂直追加到一张图像中,然后将整个动画作为两张简单的图像追加或覆盖。这有点像将两条胶片条并排粘在一起,形成一条更宽的胶片条。
|
![]() |
gif2anim
”脚本恢复这些时序,但这样做有点违背使用此方法的目的,你也可以使用第一个动画追加技术,通过将各个帧追加为临时文件来实现。由于你是将动画追加为简单的图像,因此可以将一系列动画同时追加在一起(形成一个更宽的“胶片条”),这就是这种技术如此实用的原因。例如,你可以将其与所有使用相同时序的动画字体一起使用。尽管我发现,虽然很多动画字体具有相同的帧数,但它们通常对每个字母的时序略有不同,以便使动画字母不同步(参见分割动画,了解为什么这样做是可取的)。另一方面,霓虹灯招牌应该具有同步的动画时序,因此我将使用它作为示例...
magick \( neon_h.gif -coalesce -append \) \ \( neon_e.gif -coalesce -append \) \ \( neon_l.gif -coalesce -append \) \ \( neon_l.gif -coalesce -append \) \ \( neon_o.gif -coalesce -append \) \ +append -crop x60 +repage -set delay 100 neon_hello.gif |
![[IM Output]](../images/neon_h.gif)
![[IM Output]](../images/neon_e.gif)
![[IM Output]](../images/neon_l.gif)
![[IM Output]](../images/neon_l.gif)
![[IM Output]](../images/neon_o.gif)

![[IM Output]](neon_hello.gif)
magick neon_h.gif'[0]' neon_e.gif'[0]' neon_l.gif'[0]' neon_l.gif'[0]' \ +append \( +clone \) -append \ \( neon_o.gif -coalesce -append \) +append \ \( +clone \) -append \( +clone \) -append \( +clone \) -append \ -crop x60 +repage -set delay 3 \ \( -clone 0 -set delay 300 \) -swap 0,-1 +delete \ \( -clone 1 -set delay 10 \) -swap 1,-1 +delete \ \( +clone -set delay 200 \) +swap +delete \ -quiet -layers OptimizeFrame neon_hell.gif |
![[IM Output]](neon_hell.gif)
-delay 10
”)。实际上,这个 GIF 动画的优化比你想象的要小得多,因为涉及的帧数很多。基本上,IM GIF 优化器发现它只需要每隔一帧重新覆盖“O”动画,并且使用“前一帧”处置来恢复先前点亮的“O”。因此,动画的大小仅比基本的闪光未优化“hello”图像大 50% 左右。自己看看吧。你能改进霓虹灯动画吗?让它更真实?很可惜 GIF 动画没有声音。拆分动画
现在我们已经将动画重新拼接在一起,让我们尝试将它正确地分割,以便在 Web 服务器上使用,这样各个部分就可以分别进行动画,而不会相互干扰。实际上,这相当困难,我不会尝试完全自动化这个过程。但是,WWW 上有一些工具可以做到这一点。首先,我们需要研究动画,找到整个周期内哪些部分发生了变化。为此,我们需要找到每一帧之间的差异,将它们全部加在一起,形成一张地图,显示正在动画的区域,以及完全静止的区域。这很棘手。基本上,使用 多图像 Alpha 合成 来查找动画每一帧之间的 “差异
” 图像。这些灰度差异图像加在一起,然后通道分离并也加在一起。最后,一个阈值将任何动画帧之间非零的变化变成纯白色。结果是黑色图像,在图像发生变化的任何地方都有白色,突出了变化的区域。
magick bag.gif -coalesce -set delay 0 \ -bordercolor red -border 0 -alpha off null: \ -duplicate 1,1--2 -compose difference -layers composite \ +delete -compose plus -background black -flatten \ -separate -flatten -threshold 0 bag_areas.gif |
![[IM Output]](bag.gif)

![[IM Output]](bag_areas.gif)
所以让我们用一些简单的 动画视窗裁剪 来完成这件事。
|
|
-layer
” 方法 “RemoveDups
” 来定位和合并合并动画中此类重复帧的计时。以下是在所有三个分离动画中进行最终优化的结果,包括计时更改以改善子动画的整体不同步。我还将所有三个动画并排显示在页面上,就像它们应该显示的那样。
|
|
![[IM Text]](bag_orig_size.txt.gif)
![[IM Text]](bag_opt_size.txt.gif)
远距离变化帧分割


合并时间不相交的动画
在合并两个动画以同步运行之前,你需要确保所有动画使用相同的帧数,并使用相同的延迟集。合并的难度实际上取决于动画的计时间隔。如果时间延迟基本上是恒定的,你可以简单地忽略它们,并在以后修复计时。在一个 IM 论坛讨论 中给出了一个可以忽略时间将 2 帧动画与 6 帧动画合并的示例。此外,如果总循环时间有很大差异,你可能需要进行调整,以便一个动画循环 2 或 3 次,以填充另一个动画的循环时间。基本上,计时才是最重要的。- 可能类似于…
- + 找出并调整动画以获得共同的总循环时间
- + 合并两个动画以删除任何帧优化。
- * 将帧时间延迟转换为动画开始以来的时间。
- * 适当地加倍帧以实现时间同步。
- * 将动画开始以来的时间转换回帧时间延迟。
- + 按需叠加合并的时间同步帧。
- + 最佳地合并并删除任何 “零延迟” 帧。
- + 重新优化新的动画。
-layer
” 方法,以时间同步具有相似总循环时间持续时间的两个动画。

Example, time disjoint, but same cycle time... For example suppose you have two animations of three frame with time delays of 10 10 10 5 5 20 Both animations are 30 time units long already so that is not a problem. Now magick the above to the time index when each frame should appear... and show the overall time line at which frames appear... 0 10 20 |__ NOTE that both animations 0 5 10 | end or loop at 30 From this you can see that you need to insert some extra frames to make them match. The first frame of the first animation needs to be repeated at time index 5 0->5 10 20 0 5 10 And the last frame of the second animation also needs to be duplicated at time index 20 0->5 10 20 0 5 10->20 The arrow '->' in the above means the same frame is just repeated (duplicated) into the next time index. They are actually the same image. Now that the timings of the frames in both animations are the same, you can simply merge (composite) the frames together, to get final animation that is 4 frames long. The four frame will thus have time delays of 5 5 10 10 which still add up to 30 time units (overall time per loop cycle) Current state of development.... While IM can help gather time delay information (try the '-t' option for "gif2anim") and build the animation. IM can't perform the time synchronization needed for two separate coalesced animations. This may become a special built-in option. That is, you will need figure out and double up appropriate coalesced animation frames so as to change two time-disjoint animations into two time-synchronized animations. Once you have the animations time synchronized, you can then simply use the new "-layers Composite" method, to overlay or merge the two time-synchronized animations together very easily. All the above however assumes the total loop time of the two animations are at least roughly equal, or not a major concern. Simplified Solution A simplified limited solution has been Discussed on IM Forums, for use with fast changing animations (similes). The solution takes each animation and expand it so that the animation has a fixed frame rate. That is, all frames are duplicated so that each frame is shown for a conatant 6 centi-seconds each. As such one frame with a 22cs delay may be replaced by 4 x 6cs frames (24cs total). After this the animations are further modified so that short animations are looped multiple times so that the two animations are finally of equal length. That is, the two animations are made the same overall length in terms of both time, and number of frames. Once both animations has the same frame-rate and the same length, Layer Composition can be used to merge/overlay the two animations, in the right position. The result can then be optimized using Remove Duplicate Frames to remove any extra unwanted frames (with appropriate timing adjustments and other Optimizations applied before saving. This method of having all your component animations in a fixed frame length form is especially well suited to animation libraries. ----- Other example to create.... * Overlay two moving equal time animations into a single animation (dancing butterflies, circling atoms, or birds?) This should be a straight layers composition. * Overlaying a moving animation on a fix background. (displace animation linearly with time) * Overlay two animations with different numbers of frames but constant time delays (see IM Forum Discussion). * Oveylay two time disjoint animations (as outlined above) * Overlay a simple animated figure, on an animated background. (full animation merge)