ImageMagick 示例 --
动画优化

索引
ImageMagick 示例前言和索引
优化简介
ImageMagick 的通用 GIF 优化器
帧优化
半透明处理
颜色优化
压缩优化
次要优化
GIF 优化其他信息来源
这些示例开始使用基本动画处理,尝试优化动画的最终显示和文件大小。这对于复杂的 GIF 动画尤其重要,其中可以使用较小的子帧叠加,以及三种控制动画处理方式的处置方法。

动画优化简介

优化动画并不容易,尤其是 GIF 动画,它具有颜色限制,以及不同的帧处置技术的选项,以及能够从一帧到下一帧使用较小的“子帧”叠加。在优化动画时,应尝试按照以下顺序进行优化。然而,这不是我们查看这些优化技术的顺序。对于 GIF 动画,帧优化是最基本的优化技术,并且可以从中获得最大的收益。因此,我们将首先对其进行探讨。用户可能难以处理的优化方面可能是颜色优化,这是由 GIF 动画的颜色限制引起的。其中一个方面单个全局颜色表必须作为保存为 GIF 之前的最后一步完成,否则您可能会丢失操作员对最终 GIF 文件保存的影响。

ImageMagick 的通用 GIF 优化器

-layers”方法“Optimize”将使用我们将在下面详细讨论的一些技术,尝试在一个合理的步骤中优化 GIF 动画。目前,此选项等效于(按顺序)…此时,您可以立即保存 GIF 动画。这些是可以在大多数动画序列上应用的相当安全的优化步骤,但是不能保证它会导致 GIF 动画变小。对于原始视频序列,情况尤其如此,其中透明度优化通常会导致 LZW 压缩率下降。但是对于大多数涉及卡通图像的 GIF 动画,“Optimize”操作符应该会产生一个良好且经过良好优化的动画。但是,该操作符仍在开发中,将来可能会包含其他标准优化步骤,例如…
  • alpha 通道的 50% 阈值,就像 IM 在保存到 GIF 文件格式时通常所做的那样,以删除半透明像素。如果您愿意,您仍然可以提前自己进行半透明处理以覆盖此操作。有关更多详细信息,请参阅GIF 布尔透明度
  • 某种颜色优化技术。确切是什么,还有待确定,并且可能会根据动画和涉及的颜色数量进行选择。欢迎提出建议
  • +map”操作的单个全局颜色表
换句话说,希望“Optimize”最终成为 IM 通用 GIF 动画优化器,以便 IM 用户能够快速轻松地使用。在此之前,请谨慎使用它,尤其是在脚本中,因为它会发生变化。当然,对于特定动画而言,许多优化步骤可能不值得付出努力。此选项也可能变得非常慢。这是计划,也是此 IM 示例部分所期望的目标。

帧优化

帧优化基于叠加较小的子图像,而不是整个图像的完整叠加。这显然会产生较少的像素数量,从而产生较小的磁盘文件,以便发送到网络。此外,叠加较小的帧意味着客户端计算机不必在更改屏幕上的像素方面做太多工作。但是,GIF 格式中提供了不同的处置方法来处理显示的最后一帧,这会导致不同的叠加大小。不仅如此,还可以将叠加拆分为多个部分或更新操作,从而带来更复杂但更优化的动画。由于执行帧优化的复杂性,任何现有的帧优化通常都会首先使用“-coalesce”操作删除。请参阅合并示例。当然,这意味着任何可能存在的手动优化也会被删除,因此建议谨慎操作。

基本帧优化

-deconstruct”方法将为 GIF 动画生成基本帧优化。但是,正如上一节的分解示例所示,当涉及透明像素时,此操作符并非适用于所有 GIF 动画。具体来说,当动画将任何彩色像素清除为透明时。也就是说,它仅适用于叠加动画。“-layers”方法“OptimizeFrame”旨在成为 GIF 帧优化器,它将尝试使用任何 GIF 处置方法找到最小的子帧叠加图像。结果通常是混合处置动画,尽管通常它也会生成清除帧动画纯叠加动画,如果确定这是特定动画的最佳解决方案。请记住,输入动画必须是“合并动画”,因此它由一系列完整的图像帧组成,所有帧的大小相同,没有任何画布偏移。当然,合并动画中任何现有的处置方法都完全无关紧要,并且会被“OptimizeFrame”方法忽略。例如,让我们尝试使用上一节中创建的处置前一帧动画

  magick canvas_prev.gif -coalesce  -layers OptimizeFrame  optframe.gif
  gif_anim_montage optframe.gif optframe_frames.gif
[IM Output]
[IM Output] ==>
==> [IM Output]
如您所见,“-layers OptimizeFrame”正确地将我们的动画恢复到其原始帧优化形式,使用前一帧处置。此优化甚至可以正确处理更难以处理的背景处置动画

  magick canvas_bgnd.gif -coalesce  -layers OptimizeFrame  optframe_bgnd.gif
  gif_anim_montage optframe_bgnd.gif optframe_bgnd_frames.gif
[IM Output]
[IM Output]
动画使用背景处置进行了完美的帧优化。此操作符将适用于所有 GIF 动画,并且通常会返回可能的最佳简单“处置和帧优化”。
现在,关于任何类型的简单帧优化(例如 IM 提供的)的一些坏消息……虽然“OptimizeFrame”返回 IM 可以计算出的给定动画的最佳帧优化,但有一些特殊情况它效果不佳。这些包括…
  • 需要像素清除(恢复为透明)的动画,但帧叠加过大,无法有效清除需要清除的小区域像素(请参阅下面的移动孔洞动画)。
  • 涉及两个或多个彼此远离的小变化区域的动画。这些实际上非常常见,并且难以进行帧优化。(请参阅下面的分割帧更新
  • 具有非常复杂的背景且长时间(超过 3 帧)保持静止,然后稍微更改然后再保持静止一段时间,等等,等等……或者一个静止的背景在很短的时间内变得非常模糊。对于任何计算机算法来说,在这种复杂的情况下找出“最佳”帧优化几乎是不可能的(即:什么应该被视为静止背景?)。只有人类凭借他们对所见内容的直观理解,才能在这种情况下生成良好的优化帧叠加序列。
需要难以优化的动画示例,请贡献。如果您发现 IM 无法产生良好优化的动画示例,请将其邮寄给我以供进一步研究。这就是如何开发新技术和可能的自动解决方案的方法。我自然会发布您的姓名作为贡献者。

无像素覆盖- 每隔一帧重复图像

[动画] 有时,图像的最佳优化根本不涉及叠加任何像素!例如,右侧是一个简单的动画,由 nixscripter 贡献。如果我们查看它的帧,我们可以看到它没有得到很好的优化。但请注意,动画的每隔一帧只是重复的。

  gif_anim_montage paddleball.gif paddleball_frames.gif
[IM Output]
帧优化后,我们得到了一个非常特殊的 GIF 处置序列。

  magick paddleball.gif -coalesce -layers OptimizeFrame  paddleball_opt.gif
  gif_anim_montage paddleball_opt.gif paddleball_opt_frames.gif
[IM Output]
[IM Output]
发生的情况是,IM 选择使用“前一帧 GIF 处置来恢复第一张图像,而不是叠加原始帧。由于恢复的帧保持原样,因此没有更改的像素。因此,子帧叠加减少到零。不幸的是,IM 或 GIF 格式都不允许您拥有大小为零的图像,因此改为使用一个特殊的透明像素最小图像。此图像称为丢失的图像,因为它在“-crop”“错过”实际图像数据时也会被广泛使用,从而产生相同的结果。此图像实际上仅保留帧的元数据,例如:处置方法时间延迟循环迭代。因此,它是动画的重要组成部分,即使它是“空”的。因此,通过叠加一个最小的单个透明像素,IM 在此动画中节省了大量空间(和时间)。

移动孔洞动画- 难以帧优化

这是一个 GIF 动画的极端案例,通过任何正常的优化方法都无法很好地进行帧优化。此动画基本上由一个简单的、不变的背景图像组成,但背景上有一个透明的“孔洞”,该孔洞从一帧到下一帧改变位置。为了创建它,我需要制作一个合并的图像序列,在其中使用图层 Alpha 合成在一个固定的背景图像中剪出一个孔洞。我还使用了“+antialias”开关以确保仅使用四种颜色:三种蓝色和透明度。因此,我们不需要处理颜色优化问题

  magick +antialias -size 100x100 -delay 100 xc:SkyBlue -loop 0 \
          -fill DodgerBlue -draw 'circle 50,50 15,25' \
          -fill RoyalBlue  -draw 'circle 50,50 30,25' \
          null: \( -size 100x100 xc:none -draw 'circle 40,25 27,22' \) \
                \( +clone -rotate 90 \) \( +clone -rotate 90 \) \
                \( +clone -rotate 90 \) -compose DstOut -layers Composite \
          -set dispose background  moving_hole.gif
  gif_anim_montage moving_hole.gif moving_hole_frames.gif
[IM Output]
[IM Output]
如您所见,动画有效,圆形“孔洞”显示了此页面的背景颜色,生成了大小为[IM 文本]字节的动画文件。因此,让我们尝试对此动画进行简单的帧优化。


  magick moving_hole.gif  -layers OptimizeFrame  moving_hole_opt.gif
  gif_anim_montage moving_hole_opt.gif moving_hole_opt_frames.gif
[IM Output]
[IM Output]
等等,什么也没发生!IM 能达到的最佳优化是根本没有任何变化!上面这个动画的合并版本是否是其最优化的版本?好吧,对于这个动画本身来说……是的,这确实是通过纯帧处理优化所能达到的最佳简单优化!不太好。问题在于,GIF 动画要“清除”或“擦除”前面帧绘制的像素,需要使用“背景”处理方法。尽管在某些特殊情况下也可以使用“前一帧”处理方法。但是“背景”处理只能清除刚刚覆盖的区域。由于第一帧完全覆盖了整个图像,因此整个图像都会被清除。即使动画中只有一小部分需要清除其像素。结果,需要覆盖第二帧的全部内容,即使该帧的大部分内容之前刚刚显示过!这种糟糕的“两难境地”一直持续到动画的其余部分,没有产生任何基本的帧优化。我确实说过这个动画很难进行帧优化。

帧加倍- 一种对“孔洞”进行帧优化的方案

然而,并非一切都失去了希望。通过向动画添加一些额外的帧,您可以为“OptimizeFrame”方法提供一些空间,以便更好地利用 GIF 处理方法。例如,我们通过复制第一张图像来添加一个额外的帧,但将其时间延迟设置为零,以免改变动画的整体时间安排。

  magick moving_hole.gif[0] -set delay 0   moving_hole.gif \
          -layers OptimizeFrame    moving_hole_dup.gif
  gif_anim_montage moving_hole_dup.gif moving_hole_dup_frames.gif
[IM Output]
[IM Output]
通过复制第一帧,动画的大小从 [IM 文本] 字节减少到 [IM 文本] 字节。因此,即使动画现在有五帧,但由于子帧图像叠加大小的大幅减少,其整体大小现在要小得多。复制实际上将处理方法的像素清除功能与下一帧执行的像素叠加功能分离开来。处理和叠加都是作为 GIF 动画程序同一帧更新的一部分完成的,因此不应该注意到速度或质量的损失。这是一种复杂且棘手的技术,GIF 动画设计人员或 GIF 优化程序很少见到或理解,但如果需要,其好处是值得的。然而,子帧图像大小的减少只会持续很短一段时间,因为后面的帧也必须清除下一帧的像素,因此帧会再次变大以继续清除后面的像素。也就是说,因为像素清除总是导致帧变大,而不是变小。所以让我们尝试复制所有帧(最后一帧除外,它永远不需要复制),看看这对最终图像有什么影响……

  magick moving_hole.gif  \( -clone 0--1 -set delay 0 \) \
          +delete -insert 2 -insert 1 -insert 0 \
          -layers OptimizeFrame  moving_hole_double.gif
  gif_anim_montage x2 moving_hole_double.gif moving_hole_double_frames.gif
[IM Output]
[IM Output]
如您所见,虽然我们几乎拥有两倍的帧数,但所有图像的大小都小得多,生成的动画大小为 [IM 文本] 字节,结果更小,尽管没有我们执行的第一次单帧复制那么大的节省。为了便于您了解发生了什么,'背景' 帧与前一帧完全相同,对显示内容没有任何更改。但是,它定义了在叠加下一帧图像之前需要清除的动画区域。然后,以下“”帧填充需要更改的像素,以及前一帧处理也清除的像素。在上面的动画中,这意味着需要塑造新孔洞的像素,以及用于填充先前“孔洞”的像素。结果更小,但没有那么多,因为添加额外的帧确实有其自身的成本。至少每个添加的帧也没有自己的调色板,否则这个动画实际上会变得更大,因为额外的调色板的大小!

图层优化加- 自动帧复制优化

我很高兴地说,从 6.2.7 版本开始,IM 现在可以自动进行帧复制优化,作为其正常的帧优化处理的一部分。但是,添加帧以使动画更小是一个非常激进的举动,因此它被赋予了自己的单独的“-layers”方法“OptimizePlus”。例如,让我们让 IM 进行帧复制优化……

  magick moving_hole.gif  -layers OptimizePlus   moving_hole_oplus.gif
  gif_anim_montage x2 moving_hole_oplus.gif moving_hole_oplus_frames.gif
[IM Output]
[IM Output]
也就是说,IM 给你的结果与我们之前的帧复制示例相同。因此,GIF 文件的大小仍然为 [IM 文本] 字节。但是“OptimizePlus”只有在生成的动画(3 帧)的当前帧和下一帧的像素数减少时才会进行帧复制,因此我们可以让 IM 决定是否进行帧复制。由于“-layers”方法“OptimizePlus”在创建帧优化 GIF 动画时添加了额外的帧,它还会删除任何不必要的或额外的帧,这些帧对最终动画没有任何更改(根据需要合并延迟时间)。也就是说,它还会自动执行“RemoveDups”(参见下文)。“OptimizeFrame”方法不会这样做。

删除重复帧- 合并连续的重复图像

不幸的是,如果您合并此动画,您也会获得上述添加的所有额外帧。

  magick moving_hole_oplus.gif -coalesce gif:- |\
     gif_anim_montage x2 - moving_hole_oplus_cframes.gif
[IM Output]
为了让您从合并的动画中删除此类无用的重复帧,提供了一种“RemoveDups”方法。它将动画中的每一帧与其下一帧进行比较,如果它们相同(颜色相似度由当前的模糊因子设置),则删除第一帧。此外,为了确保动画中的任何时间安排都不会丢失,这两个帧的时间延迟也会合并。例如……

  magick moving_hole_oplus.gif -coalesce -layers RemoveDups  gif:- |\
     gif_anim_montage - moving_hole_oplus_rmdups_frames.gif
[IM Output]
现在我们有了动画的原始合并形式。有关删除额外帧的另一种方法,请参阅下面的“RemoveZero”方法。

分割帧更新- 分别更新两个距离较远的更改

正如您在帧复制中所看到的,通过将“像素清除”与新像素的叠加分开,我们可以减少单个帧叠加的整体大小。但是此动画仍然会产生一些非常大的叠加,这些叠加主要由从一帧到下一帧实际上没有发生变化的像素组成。也就是说,主要叠加帧仅更新两个相当小的区域,这两个区域彼此相距甚远,从而产生单个大型叠加图像。与其尝试同时更新这两个更改,同时还包括这两个区域之间所有未更改的像素,不如分别更新每个区域。也就是说,我们将帧更新分为两个阶段,每个阶段对应一个分离的更改区域。在这种情况下,我们可以先填充孔洞,然后创建新孔洞作为单独的更新。实际上,这两个分离更改的顺序并不重要(除了可能与处理有关),但您应该尝试对此进行逻辑上的考虑。也可能一个更改比另一个更改更容易创建。例如,在这里我插入额外的帧以填充旧孔洞,作为对“挖掘”新孔洞的单独更新。这是更容易生成的中间帧,也是最符合逻辑的动作顺序。当然,您不需要为最后一帧执行此操作,因为该帧在动画循环之前就被丢弃了。

  magick moving_hole.gif \
          \( +antialias -size 100x100 -delay 0 xc:SkyBlue \
             -fill DodgerBlue -draw 'circle 50,50 15,25' \
             -fill RoyalBlue  -draw 'circle 50,50 30,25' \) \
          \( +clone \) -insert 1 \( +clone \) -insert 3  +swap \
          -set dispose background  moving_hole_split.gif
  gif_anim_montage x2 moving_hole_split.gif moving_hole_split_frames.gif
[IM Output]
[IM Output]
请记住,添加的中间帧与周围用户显示的帧(具有非零时间延迟的帧)不同。这不是简单的“帧复制”,而是将两个距离较远的微小更改分开。添加中间帧不是一个可以自动化的简单步骤。尽管有可能开发出一种智能启发式方法来生成这些中间帧,但并不总是清楚应该做什么,更不用说是否应该做了。如果您想尝试生成这样的启发式方法,请给我发邮件。所以让我们在添加这些额外帧后尝试标准帧优化……

  magick moving_hole_split.gif \
               -layers OptimizeFrame     moving_hole_split_opt.gif
  gif_anim_montage x2 moving_hole_split_opt.gif \
                      moving_hole_split_opt_frames.gif
[IM Output]
[IM Output]
添加这些“零延迟中间帧”使此动画能够比原始未优化的动画更好地进行帧优化,生成一个 [IM 文本] 字节的动画。但是对于这种情况,它不如使用自动帧复制技术(参见上面的“OptimizePlus”图层方法)。但是添加“零延迟中间帧”并不会阻止您也使用“帧复制”技术……

  magick moving_hole_split.gif \
               -layers OptimizePlus moving_hole_split_oplus.gif
  gif_anim_montage x2 moving_hole_split_oplus.gif \
                      moving_hole_split_oplus_frames.gif
[IM Output]
[IM Output]
此动画现在每个帧更新有两个额外的“零延迟中间帧”。第一个填充旧孔洞,第二个清除一个将包含透明像素的区域,最后恢复不应该清除的像素。结果是针对此特定问题动画可能实现的最优帧优化,最终文件大小为 [IM 文本] 字节。也就是说,我们的 4 帧动画通过添加 6 个额外的零时间延迟帧而变得更小!超过原始帧数的两倍。很奇怪但却是真的!当然,如果 GIF 动画程序能够真正识别零延迟中间帧的本质,即动画真实帧之间的中间更新,那就太好了。但即使如此,当更新高度分离且非常小时,额外帧造成的轻微暂停也很少可见。
当然,如果动画的两个分离部分实际上没有关联,那么它们不需要时间同步。另一种选择是,与其添加额外的帧,不如将动画拆分为两个完全独立的动画,您可以在网页上一起显示它们。请参阅拆分动画。但是,此特定动画无法拆分为单独的时间不相交的动画。首先,距离较远的更改需要时间同步。其次,四个发生更改的区域在水平和垂直方向上都重叠。这意味着简单的 HTML“表格”无法将子动画重新组合成一个完整的整体,除非使用某种 CSS 技巧。你能证明我错了?未来:在“动画处理”中引用一个关于“两个距离较远的物体”动画的更好的例子,例如涉及两个分别移动的物体。

删除零延迟帧- 删除中间更新

当然,有时您不感兴趣或想要从动画中删除这些添加的中间帧,只留下实际显示给用户一段时间内的帧。您不能只是合并动画并使用“RemoveDups”方法,因为并非所有“中间帧”都与周围帧相似,因此不是重复帧。但是,由于这些类型的帧具有零时间延迟,因此您可以使用另一种特殊的“-layers”方法“RemoveZero”,它将删除任何具有零时间延迟的帧。此方法还会删除使用帧复制和“OptimizePlus”技术添加的帧。例如……


  magick moving_hole_split_oplus.gif -coalesce -layers RemoveZero gif:- |\
     gif_anim_montage - moving_hole_split_rmzero_frames.gif
[IM Output]
这再次将动画恢复到仅用户可见的帧,简化了动画。当然,在移除零延迟中间帧之后,很难重新添加它们,因为更改信息已丢失。因此,动画之后可能无法很好地进行帧优化。毕竟,优化是此类帧的主要目的之一。

帧优化结果和总结

让我们总结一下我们对移动孔动画的优化...
[IM Text]
如您所见,通过使用一些复杂的帧处理,在 IM 和一些人工干预的帮助下,我们能够将“移动孔”动画的帧优化到几乎原来的一半大小,尽管帧数是原来的近三倍。当然,不同动画的结果可能会有很大差异,但我们用于帧优化的技术是相同的。它只需要一点小心和预先考虑,人类擅长这一点,而计算机不擅长。
问题在于,IM 不仅应该考虑当前正在查看的帧集中的像素数量,还应该考虑添加的额外帧的总体大小,以及可能获得的整体压缩结果,以便在决定如何优化图像帧时做出决定。

另一方面,IM 也不会考虑可能产生的像素数量的节省结果,而不仅仅是直接相关的帧。也就是说,由于帧加倍或使用的处理方法,后续帧的大小也可能更小。当选择是使用“前一图像处理”方法时,这一点尤其正确,该方法可以在动画序列的后面显着减少像素数量,而不是在下一帧中立即减少。这里做出好的选择通常需要人工输入。

因此,我无法保证 IM 会为特定动画做出最佳优化选择。但是,它当然会尝试在不使用递归的情况下做出选择。也就是说,仅使用其决策的直接像素计数。

递归算法,一种做出选择然后查看由此选择产生的动画的最佳最终大小(包括后续的递归选择)的算法,可以产生保证的最佳优化。但是它也可能是一个非常慢的操作符,对于大型动画来说,可能需要数年时间才能做出最终决定。它还需要包含压缩优化选择,因为这些选择可能会影响最终结果。换句话说,虽然这样的算法可以保证最佳优化,但它是以巨大的计算成本为代价的。

当然,对动画试图实现的目标有深入了解的人类通常会在复杂的动画中做得更好,就像您上面在拆分帧更新中看到的那样。

如果您想尝试创建一个递归 GIF 优化操作符,请尽管尝试。我将尽我所能提供帮助。它将击败市场上几乎所有其他 GIF 优化程序。此外,大多数 GIF 动画开发人员可能会非常感谢您的努力(金钱方面)。

半透明处理

GIF 文件格式不允许使用半透明像素(请参阅GIF 布尔透明度)。这是一个事实,在您正确优化动画或甚至将其保存为 GIF 格式之前,您需要以适合动画的方式处理可能存在的任何半透明像素。默认情况下,如果您不处理这些像素,IM 将使用 50% 的阈值将这些像素转换为完全透明或完全不透明。但是,这可能不是处理问题的最佳方法,尤其是在包含大面积半透明像素的图像中,例如阴影效果。例如,我想创建一个星际之门阿斯加德传送动画,该动画可以将几乎任何子图像作为被传送的对象。

  magick -channel RGBA -fill white \
          \( medical.gif -repage 100x100+34+65 -coalesce -set delay 200 \) \
          \( +clone -motion-blur 0x20+90 -blur 0x3 -colorize 100% \
                +clone -colorize 30%  +swap  -composite  -set delay 10  \) \
          \( +clone -roll +0-20 -blur 0x3 -colorize 30% \
             -motion-blur 0x15+90 -motion-blur 0x15-90 -set delay 10 \) \
          \( +clone -colorize 30% \
             -motion-blur 0x30+90 -blur 0x5 -crop +0+10\! \) \
          \( +clone -motion-blur 0x50+90 -blur 0x2 -crop +0+20\! \) \
          \( +page -size 100x100 xc:none -set delay 200 \) \
          -set dispose background -coalesce   -loop 0     teleport.miff
  gif_anim_montage teleport.miff teleport_frames.png
[IM Output]
我故意将动画保留在 IM 内部 MIFF:文件格式中,因为这确保了原始图像在未经修改的情况下得以保留,并使用 PNG:文件格式显示帧,以便您可以看到其中包含的所有半透明像素!这不仅对于具有半透明像素的动画很重要,而且对于具有大量颜色的动画也很重要。一旦图像序列保存到 GIF 中,您生成良好颜色优化的机会就会从良好变为困难。
好的,我有一个动画序列。如果我尝试将其直接保存为 GIF,IM 将只对所有这些半透明像素进行阈值处理。

  magick teleport.miff teleport_thres.gif
  gif_anim_montage teleport_thres.gif teleport_thres_frames.gif
[IM Output]
[IM Output]
结果看起来与我们想要的完全不同。默认的 50% 透明度处理使动画看起来像一个收缩的“蛋”。绝对不是我想用这个动画实现的目标。如果这种类型的透明度处理是可以接受的,那么这就是在继续其他优化之前应用它的方法...

  magick teleport.miff -channel A -threshold 50% +channel \
                 ...do further processing now...       teleport.gif
使用上述 DIY 的额外优势在于您可以控制阈值水平。例如,使用“10%”去除几乎所有存在的半透明像素,使用“90%”将它们全部设为不透明。

  magick teleport.miff -channel A -threshold 90% +channel teleport_thres90.gif
  gif_anim_montage teleport_thres90.gif teleport_thres90_frames.gif
[IM Output]
[IM Output]
但是,对于像这样的动画应用阈值并不是一个好的解决方案,因为它确实破坏了我试图实现的透明效果。
保留上述动画中所有特殊效果的最佳整体解决方案是只需添加纯色背景

  magick teleport.miff -bordercolor skyblue \
                  -coalesce -border 0 teleport_bgnd.gif
  gif_anim_montage teleport_bgnd.gif teleport_bgnd_frames.gif
[IM Output]
[IM Output]
这消除了动画中的所有透明度,但代价是只能让动画在特定背景颜色下工作。但是,如果您正在为特定的网页创建动画,这可能是可以接受的。但是请注意,对于具有清晰轮廓的图像,使用这样的抖动图案可能会在锐利边缘产生“点状”轮廓。因此,不建议用于一般情况。另一种解决方案是尝试生成一些透明和不透明像素的图案,以试图保留图像的半透明度。为此,IM 提供了大量可以解决此问题的抖动选项。未来:一些指向关于透明度抖动的待创建部分的链接,例如量化和抖动请注意,使用单色抖动 alpha 通道的明显第一个解决方案并不简单,可能需要一些高级多图像合成才能正确执行。
一个简单的解决方案是使用扩散像素有序抖动技术,该技术可以仅限于 alpha 通道,以去除半透明像素。

  magick teleport.miff -channel A -ordered-dither o8x8  teleport_od.gif
  gif_anim_montage teleport_od.gif teleport_od_frames.gif
[IM Output]
[IM Output]
结果还可以,但看起来像是物体溶解而不是传送。
使用半色调将产生更好的效果,使透明度图案更大胆。

  magick teleport.miff -channel A -ordered-dither h8x8a teleport_htone.gif
  gif_anim_montage teleport_htone.gif teleport_htone_frames.gif
[IM Output]
[IM Output]
但是对于此特定动画,我发现使用用户设计的抖动映射生成垂直线(来自水平线抖动图案)会产生一种增强传送动画并去除半透明像素的效果。

  magick teleport.miff -rotate 90 \
          -channel A -ordered-dither hlines -rotate -90 teleport_lines.gif
  gif_anim_montage teleport_lines.gif teleport_lines_frames.gif
[IM Output]
[IM Output]
因此,如您所见,处理 GIF 动画中的半透明度有很多可能性。

颜色优化

处理半透明像素只是 GIF 文件格式的第一个限制。下一个是动画中每个颜色表最多 256 色的限制。您可以为每个帧提供单独的颜色表。这意味着单个动画可以包含超过 256 种颜色。但是,即使那样也可能并不总是好的主意。如果您只想快速了解可用的颜色优化选项的摘要,我建议您跳到视频到 GIF转换的示例,在该示例中,动画的颜色问题最严重。

GIF 颜色问题

GIF 动画在处理颜色方面尤其存在问题,因为它首先不允许半透明颜色,然后每个帧或全局颜色限制为 256 色。最后,除非一个帧中用于像素的颜色在下一帧中也与相同颜色匹配(当图像的那一部分没有改变时!),否则您最好的帧优化将无法很好地工作。这看起来可能是一个简单的问题,但颜色减少本身就是一个极其复杂的领域,需要在 IM 示例中拥有自己的完整部分。颜色问题实际上是您在万维网上找到的大多数 GIF 动画都是卡通类型或外观非常糟糕的原因。尤其是在从动画的较大版本调整大小后。在调整动画大小中,可能需要花费比实际调整大小过程本身更多的精力来进行颜色优化。在这里,我假设您拥有动画的原始源代码。但这并不总是可能的,因此,如果您正在优化修改后的 GIF 动画,则可能需要格外小心。但是,如果您有一个颜色过多的动画,您需要记住的第一件事是...
不要直接保存到 GIF 格式,
使用 MIFF 文件格式,  或   分开的 PNG 图像。
一旦保存到 GIF,您就失去了对 GIF 颜色优化工作的控制,并且您可能得到一个外观非常糟糕的 GIF 动画,使用各种帧优化技术无法很好地优化它。

速度动画- 颜色过多的动画

首先,我们需要生成一个具有大量颜色的 GIF 动画,以便我们能够真正测试颜色优化中涉及的问题。

  magick -dispose none -channel RGBA \
          \( medical.gif -repage 100x60+5+14  -coalesce -set delay 100 \) \
          \( medical.gif -repage 100x44+34+6  -coalesce -set delay 10 \
             -motion-blur 0x12+0  -motion-blur 0x12+180 -wave -8x200 \) \
          \( medical.gif -repage 100x60+63+14 -coalesce -set delay 100 \) \
          \( medical.gif -repage 100x44+34+6  -coalesce -set delay 10 \
             -motion-blur 0x12+0  -motion-blur 0x12+180 -wave +8x200 \) \
          null: \( +page  -size 120x15 xc:SkyBlue xc:RoyalBlue \
                   -size 120x70 gradient:SkyBlue-RoyalBlue \
                   +swap -append -blur 0x3 -background white -rotate -25 \
                \) -gravity center -compose DstOver -layers Composite \
          -loop 0   speed.miff

  magick  speed.miff  speed.gif
  gif_anim_montage  speed.gif  speed_frames.gif
[IM Output]
[IM Output]
请注意,我没有将动画直接保存到 GIF 格式,而是先将其保存到 MIFF 格式文件中,“speed.miff”。这保留了最初创建(或修改)动画的所有方面,包括 GIF 元数据、时间延迟以及图像的所有颜色,而不会失真。仅在保留原始动画后,我才将原始动画直接转换为 GIF 格式。这样我就可以展示上面代码的意图以及为什么我称之为“speed”。这样做也是为了提供一个基线 GIF 动画进行研究和以后的比较。所以让我们看看我们原始动画的各种细节..

  magick identify -format "Number of Frames: %n\n" speed.miff | head -1
[IM Text]

  magick identify -format "Colors in Frame %p: %k\n"  speed.miff
[IM Text]

  magick speed.miff +append  -format "Total Number of Colors: %k"  info:
[IM Text]
如您所见,动画中的每个图像都有非常大量的颜色。每个帧不仅具有不同的颜色数量,而且第一帧和第三帧在颜色方面非常相似,尽管并不完全相同。但是 GIF 文件格式每个帧最多只能保存 256 种颜色,ImageMagick 将其保存到 GIF 格式时,采用了最快且最笨拙的方式...它减少了动画中每个帧的颜色数量(一个称为颜色量化的过程)...

  magick identify -format "Colors in Frame %p: %k\n"  speed.gif
  magick speed.gif +append  -format "Total Number of Colors: %k"  info:
[IM Text]
由于每个帧中减少的颜色数量略有不同,因此 IM 还需要为动画中的每个帧提供单独的颜色映射。这意味着 GIF 文件有一个“全局颜色表”,它始终存在,但还有三个单独的“本地颜色表”。“magick identify”命令无法告诉您 GIF 文件有多少个此类本地颜色表,因为信息过于特定于格式,并且对于 IM 通常执行的图像处理并不重要。但是,更具体的“Giftrans”程序可以告诉您使用了多少个低级本地颜色表...


  giftrans -L speed.gif 2>&1 | grep -c "Local Color Table:"
[IM Text]
正如您所看到的,此动画有 [IM Text] 个局部颜色表,比图像中存在的帧数少一个,正如我预测的那样。每个帧不仅具有不同的颜色集,还具有略微不同的颜色模式(图像抖动模式),如 错误校正抖动的问题 中所述。通常,IM 的此默认操作 颜色量化和抖动 非常出色,非常适合图片,尤其是真实照片。事实上,动画的各个帧通常看起来很棒。所有问题都出现在我们尝试将这些单独的颜色减少的帧串联成单个动画序列时。

颜色优化前进行帧优化?

如上所示,将动画直接保存为 GIF 格式可以正常工作,但您会发现从一帧到下一帧会有相当多的颜色差异,这对以后的 帧优化(如您稍后将看到的)不利。为了防止颜色差异导致此类问题,您可以在保存动画之前进行 帧优化,从而避免引入帧与帧之间的颜色差异。但是请注意,在颜色减少之前进行帧优化会改变颜色减少的动态。优化后的子帧中,通常较少的静态不动区域会出现,这意味着该帧的颜色量化可以降低这些颜色的重要性,从而减少颜色数量。

模糊颜色优化

但是,有时您在将原始动画保存为 GIF 格式之前无法访问它。如果您从 WWW 下载了原始动画,则尤其如此。这意味着您已经拥有一个包含所有这些 GIF 颜色失真的动画,这会导致以后优化时出现问题。现在,由于从一帧到下一帧使用了一组略微不同的颜色,并且对动画中的每一帧使用了不同的像素模式,因此每一帧都可以视为一个完全不同的图像。例如,让我们比较第一帧和第三帧,它们共享大量相同的背景图像……

  magick compare  speed.gif'[0,2]' speed_compare.gif
[IM Output]
上面示例中的红色区域显示了两个差异区域的两个实心正方形区域,正如您所预料的那样。但它还显示了勾勒出两帧背景的颜色差异带。这些表示背景渐变边缘的“翻滚”抖动模式,其中使用了不同的彩色像素来表示完全相同的背景。这也是显示使用不同的颜色集和抖动模式造成的背景干扰最少的帧对。实际的连续帧差异要糟糕得多,产生了近乎实心的红色差异。
如果您的源图像使用 JPEG 图像格式存储,则此类图像差异也是一个问题。此格式使用有损压缩方法,即使在 100% 质量下,也会导致图像中出现轻微的颜色差异。但是,差异通常仅限于差异区域周围的光晕,而不是整个图像。

我只能说,除非您计划将一个单一图像用作所有帧的静态背景图像,否则请避免在动画中使用 JPEG 图像。
由于动画中的如此多像素在一帧到下一帧之间是不同的,因此当我们尝试 帧优化 动画时,根本无法优化也就不足为奇了……

  magick speed.gif  -layers OptimizeFrame  speed_opt2.gif
  gif_anim_montage  speed_opt2.gif  speed_opt2_frames.gif
[IM Output]
但是,动画帧不变部分之间的像素颜色差异大多数实际上都相当小。如果情况并非如此,那将不是一个很好的 颜色减少。这意味着通过要求 IM 放松其颜色比较,您可以要求它忽略细微的颜色差异。这是通过设置适当的 模糊因子 来完成的。

  magick speed.gif  -fuzz 5%  -layers OptimizeFrame  speed_opt3.gif
  gif_anim_montage speed_opt3.gif speed_opt3_frames.gif
[IM Output]
如您所见,通过添加一个小 模糊因子,IM 现在将忽略仅略有不同的像素,从而产生合理的 帧优化。您需要多少模糊因子取决于 IM 在颜色减少原始图像时遇到了多少麻烦。在这种情况下,并不是很多,因此只需要一个非常小的因子。如果一个小模糊因子产生了可接受的结果,则只需将其设置为您的 帧优化透明度优化。请记住,您仍然需要为每一帧处理一个单独的颜色表,这是下一个讨论点。另请注意,帧优化 决定对第二帧使用“先前处理”。也就是说,在显示第二帧后,在覆盖之前将图像恢复到上一帧处理(第一图像)。这导致覆盖图像大小比始终不使用处理时要小。如果您只需要一个简单的 叠加动画,并且始终仅使用 无处理,则可以使用旧的 分解 运算符(也称为 图层比较任何)来生成它。

  magick speed.gif  -fuzz 5%  -deconstruct  speed_opt4.gif
  gif_anim_montage speed_opt4.gif speed_opt4_frames.gif
[IM Output]

生成单个全局颜色表

现在,由于每一帧都有一组不同的颜色,因此 IM 被迫保存图像,为每一帧提供一个单独的颜色表:第一帧的一个全局颜色表,以及后面帧的 3 个局部颜色表。例如,这里我使用了非常简单的程序“Giftrans”程序来报告创建了多少帧颜色表。

  giftrans -L speed.gif 2>&1 | grep -c "Local Color Table:"
[IM Text]
对于完全合并(或类似胶片条)的动画,为每一帧提供单独的颜色表是完全正常且合理的,在这种情况下,这不是问题。也就是说,对于非常不同的图像的幻灯片放映,单独的颜色表将产生最佳外观结果。因此,这是 IM 的正常工作行为。但是,所有这些额外的颜色表都非常昂贵,因为每个颜色表都可以占用大量空间。对于图像中的每一帧,最多 768 字节(256 种颜色×每种颜色 3 字节或 3/4 千字节)。不仅如此,GIF 压缩不会压缩这些颜色表,只会压缩像素数据!如果为单独的颜色表分配这么多文件空间是一个问题,尤其是在图像颜色变化不大的情况下,就像大多数 GIF 动画一样,那么您可以让 IM 仅使用所需的全局颜色表,而不是添加任何局部颜色表。---要删除局部颜色映射,所有图像都必须变为调色板类型,并且都使用相同的调色板,对于命令行,您可以通过设置“-map image”来定义命令调色板,您不能使用-colors,因为这适用于单个图像。命令行解决方案是一个特殊的“+map”选项,它对一个公共调色板进行全局颜色减少,并将该调色板添加到所有图像中。注意,对图像的任何更改都可能使调色板无效,因此,虽然颜色减少应该在执行 GIF 帧和/或压缩优化之前完成,但公共调色板需要放在最后,就在保存之前。如果“+map”不需要减少图像中的颜色数量,它不会执行此操作或抖动颜色,只需在所有图像中添加一个公共调色板。---如果所有帧都使用相同的颜色调色板,则 IM 可以生成一个单个全局颜色表。在 IM 中,颜色调色板仅通过从使用此类调色板的图像格式中读取它们或使用“-map”颜色减少运算符为其分配一个来分配给图像。有关更多详细信息,请参阅 使用预定义颜色映射进行抖动。生成此单个颜色表的一种方法是简单地“-append”将所有帧连接在一起,然后使用“-colors”命令将颜色数量减少到最小子集(小于 256,或者如果您想要更小的颜色表,则更小)。然后可以使用“-map”将生成的颜色表应用于原始图像。例如,这里将图像减少为一组 64 种颜色。这使用特殊的 MPR 内存寄存器 将生成的颜色映射分配给“-map”命令。

  magick speed.gif \
          \( -clone 0--1 -background none +append \
              -quantize transparent  -colors 63  -unique-colors \
             -write mpr:cmap    +delete \) \
          -map mpr:cmap      speed_cmap.gif
[IM Output]
现在,如果您使用“Giftrans”检查生成的动画,您会发现该图像现在使用单个“全局”颜色表,而不是为每一帧提供单独的颜色表。
在将图像连接在一起之前,我使用了“-background”颜色“None”,允许您将其用于非合并动画,并且不会增加额外的不需要的颜色。

特殊的“-quantize”设置“transparent”颜色空间用于确保 IM 不尝试在其颜色映射中生成半透明颜色。这是无用的,因为我们将结果保存为 GIF,GIF 无法处理半透明。

最后,我将颜色减少到 63 种,以留出空间用于透明颜色。一些动画需要透明度,而另一些(如这个)可能以后仍然需要透明度才能进行 压缩优化
为了简化操作,IM 还提供了一个特殊的选项“+map”,它将在所有帧上生成一个公共颜色映射(256 种颜色),并全局应用它。这比上面的 DIY 方法简单得多。

  magick speed.miff  -alpha off +map   speed_map.gif
[IM Output]
这导致在生成的图像中产生了 [IM Text] 个“局部”(或额外的不需要的)颜色表。我将在接下来的优化部分中使用动画的单一颜色表版本,尽管您实际上可以在动画优化的任何时间点执行此操作,尤其是在最终保存之前。由于颜色表优化,动画在我们的直接转换的 GIF 中为 [IM Text] 字节,现在在使用“+map”运算符后为 [IM Text] 字节。动画具有的帧数(和“局部颜色表”)越多,节省的空间就越大。现在,由于对动画的任何修改通常都会删除每个图像的保存调色板,因此在将动画保存为 GIF 之前,“+map”运算符必须是最后一个操作。请记住
删除局部颜色映射应该是保存为 GIF 格式之前的最后一个优化。

有序抖动,去除“静态”

正在建设中

但是请注意,在我们迄今为止研究的所有技术中,都可能存在一个抖动模式,该模式从一个叠加层更改为另一个叠加层。像素的翻滚看起来像电视静电。
... small number of colors ...
对于较小的静止区域进行帧优化,您甚至可以获得矩形静止区域,看起来更糟糕。...有序抖动...目前,请参阅更实用且细节较少的视频到GIF,优化总结

压缩优化

将动画保存为GIF格式后,通过处理半透明像素并使用颜色和帧优化,还可以通过迎合GIF压缩算法来获得一些较小的文件大小缩减。GIF文件格式可使用的LZW压缩或游程长度压缩,如果找到较大区域的恒定颜色或重复出现的像素序列,则压缩效果会更好。

透明度优化

如您在帧优化中所见,叠加的图像通常只是重复已显示的内容。也就是说,它正在叠加GIF处置方法应用后已存在的相同颜色的像素。但是为什么要费心重复这些像素呢?如果您已经在图像中使用透明度,则可以使用透明像素颜色。但是,将这些区域转换为透明度,可以获得更大面积的统一透明像素。与使用需要匹配正在叠加的相同区域的不同颜色的混合相比,这可以更好地压缩。例如,这是一个简单的帧优化叠加动画...
[IM Output] [IM Output]
现在让我们使用“-layers”方法“OptimizeTransparency”(IM v6.3.4-4中添加)来替换任何更改显示结果的像素为透明度。

  magick bunny_bgnd.gif -layers OptimizeTransparency \
                                    +map   bunny_bgnd_opttrans.gif
  gif_anim_montage bunny_bgnd_opttrans.gif bunny_bgnd_opttrans_frames.gif
[IM Output]
[IM Output]
如您所见,子帧现在具有较大的透明区域,这些区域不会影响最终的动画结果。需要更改像素的区域仍然会叠加,但不会更改的区域已变为透明。这包括动画对象内部,也留下了相当可怕的“孔”。由于较大的恒定透明彩色区域(理论上)会更好地压缩,因此生成的“杂乱”动画要小得多,将文件大小从帧优化的结果[IM Text]字节减少到[IM Text]字节。对于非常小的努力,这是一个相当大的节省。请注意,优化方法不需要是合并动画,并且子帧的大小保持不变,以保留此帧和后续帧的处置需求。因此,任何节省都只是在相同数量的动画像素的压缩率方面有所提高,而不是实际保存到文件中的像素数量。因此,应在完成任何所需的帧优化后,将其作为最终优化步骤之一执行。
FUTURE: link to a 'remove background' from animation
当然,与大多数其他“-layers”方法(比较或优化)一样,您可以指定模糊因子进行调整,“颜色有多相似”。这使您可以处理颜色抖动不良的动画,尽管如果您研究了上面的颜色优化,则不应该出现此问题。免费的动画GIF工具“InterGIF”也提供了与上面显示的相同类型的透明度压缩优化,但无法支持“模糊因子”以使“接近”的颜色变化也变为透明。我不推荐它,除非在IM不可用时作为替代方案。

LZW 优化- (非 IM)

某些应用程序可以进一步优化动画中图像的压缩率,使其更小。但是,这样做需要专门了解GIF图像文件格式通常使用的LZW压缩。基本上,如果LZW压缩算法已经处理了特定的像素序列,它就不会费心将其转换为透明像素,因为这样做不会提高图像的压缩效果。听起来很奇怪,但确实有效。不幸的是,ImageMagick不会这样做,因为这是一个非常复杂的过程,需要大量的技能和资源才能获得合理的启发式方法,以在一般情况下产生良好的结果。但是,我可以使用“Gifsicle”应用程序的最高“-O2”优化级别,为您提供此技术的实用示例。

  gifsicle -O2 bunny_bgnd.gif -o bunny_bgnd_lzw_gifsicle.gif
  gif_anim_montage bunny_bgnd_lzw_gifsicle.gif bunny_bgnd_lzw_frames.gif
[IM Output]
[IM Output]
LZW压缩优化将图像从简单的透明度优化后的[IM Text]字节减少到“Gifsicle”的[IM Text]字节。改进不大。然而,更重要的方面是,虽然LZW优化将未更改的像素转换为透明度(如我们上面使用透明度优化所做的那样),但它没有更改已看到的像素序列。也就是说,只有动画中尚未重复的像素组发生了变化,因为这些像素(大概)将使用LZW压缩模式得到很好的压缩。请注意,选择应将哪些像素设为透明以生成重复的像素模式非常复杂且困难,甚至可能取决于确切的LZW实现。这是一种启发式方法,而不是完全可预测的算法。因此,不同的程序通常会根据正在压缩的特定图像产生不同的结果。一个程序可能为一个图像产生更好的压缩率,而另一个程序可能对另一个图像更好。

有损 LZW 优化- (非 IM)

另一种压缩改进方法涉及稍微修改像素颜色本身以“接近颜色匹配”,以便增加图像中颜色引用的重复次数。重复的模式自然会更好地压缩,因此可以产生更高的压缩率。先前“Gifsicle”应用程序的一个分支,称为giflossy,也生成一个“gifsicle”程序,但该程序可以选择以细微的方式修改图像(它是“有损的”)以进一步减小GIF图像的大小,尤其是在动画中。

  gifsicle -O3 --lossy=80 bunny_bgnd.gif -o bunny_bgnd_giflossy.gif
  gif_anim_montage bunny_bgnd_giflossy.gif bunny_bgnd_lossy_frames.gif
[IM Output]
[IM Output]

创建日期:2007年3月22日(“动画”的细分)
更新日期:2007年4月23日
作者:Anthony Thyssen,<Anthony.Thyssen@gmail.com>
使用以下版本生成示例:[version image]
URL:https://imagemagick.org.cn/Usage/anim_opt/
这导致大小为[IM Text],这令人惊叹,尺寸减少了1/3。不幸的是,此方法涉及更改生成的图像,因此优化是有损的,因为它可能会丢失细微的颜色信息。从好的方面来说,它允许您压缩单个帧,而不是帧到帧的优化。例如,在这里我生成了先前无损LWZ压缩与有损LWZ压缩的差异图像。

  magick compare bunny_bgnd_lossy_frames.gif bunny_bgnd_lzw_frames.gif \
          bunny_bgnd_diff_frames.gif
[IM Output]
如您所见,几乎所有颜色修改都发生在原始的“草地”背景图像中,而不是卡通兔子中。基本上,它只是稍微修改了一些东西,足以产生巨大的差异,并且对于此图像来说,外观没有明显的差异。当然,颜色量化和抖动本身就是一个有损操作,并且通常也是必需的,因此,对于GIF图像和GIF动画使用有损压缩方法不被认为是非常糟糕的。
此类算法的另一个示例是Photoshop获得专利的,请参阅美国专利7031540 - 转换以在视觉失真最小的前提下提高图像的Lempel-Ziv可压缩性。这是一篇很长的文章,但详细介绍了它用于实现更好压缩的方法。

有序抖动 LZW 优化

由于抖动过程通常比LZW优化更有损,因此更好的解决方案可能是尝试将可重复的模式作为抖动过程的一部分引入。这可以通过使用有序抖动来生成此类模式,从而实现比所有以前的LZW优化方法更强的LZW压缩节省。作为一个额外的好处,它还可以改进具有静态背景的真实动画的帧优化。如果您人为地清理背景使其成为静态不变的背景,则尤其如此。当然,有序抖动压缩优化仅适用于尚未抖动或以其他方式优化颜色的图像。因此,它仅适用于尚未针对GIF图像格式进行优化的动画。此外,当前IM有序抖动仅适用于统一调色板。IM尚未具有有序抖动的“最佳颜色”或“用户提供的”调色板实现,尽管我见过一些程序将此类算法用于非常有限(且固定的)调色板。您是否了解此类算法?有关使用有序抖动进行改进的LZW压缩优化的实际示例,请参阅有序抖动视频

其他LZW优化

还可以通过图像中“抖动模式”的其他重新排列来实现LZW优化的其他改进。并且某些GIF工具可以做到这一点。但是,任何此类优化都应在批准前由人眼检查,因为有时会导致微妙但糟糕的颜色变化。

压缩优化总结

以下是使用压缩优化实现的最终文件大小的完整摘要。
[IM Text]
如您所见,通过使用非常复杂的LZW优化而不是内置的透明度优化,最终动画大小的改进很小。但是,结果在许多可用的GIF优化应用程序程序和正在优化的特定动画之间差异很大。如果您确实需要从文件大小中获取最后一个字节,那么LZW优化可能正是您需要的。如果您确实需要最好的结果,则应尝试许多不同的程序(以及启发式实现)以查看哪个程序可以更好地压缩您的特定动画,包括它们提供的其他优化功能。通常,透明度优化足以满足大多数目的。使用LZW优化只会产生略微更好的结果,从而为网络传输大小而不是磁盘存储大小产生非常小的节省,因为后者使用较大“块”或“块”的存储。正因为如此,我认为LZW优化是过度杀伤,我认为它不值得付出努力或金钱(大多数这些工具都是商业销售的)。
不幸的是,我发现这些GIF优化器无法很好地处理所有类型的预优化动画。

例如,我的测试表明,“Gifsicle”无法处理已经使用“背景处置”技术进行优化的动画。

另一方面,我发现“InterGIF”无法处理已经优化为使用初始画布和“先前处置”技术的动画。它也仅限于使用透明度优化,而 IM 现在提供了该功能。

因此,我建议您不要混合使用 GIF 优化工具,将一个工具的输出馈送到另一个工具。至少在先合并动画以移除任何先前帧优化之前不要这样做。

IM、Gifsicle 和 InterGIF 都提供了这样的合并选项来移除它们自己的优化,不过我无法保证非 IM 应用程序会正确合并所有动画。IM 会。

由于您无法可靠地将这些程序与 IM 的高级帧优化技术(自动选择和切换使用不同的 GIF 处置技术)一起使用,我经常发现 IM 通常会产生比仅使用这些 LZW 压缩优化器更好的整体结果。我还建议您之后再次合并结果,并将它的帧与原始未优化的动画进行比较,以确保非 IM 程序没有以某种方式完全搞砸了动画(参见上面的注释)。相信我,我见过这种情况发生,脚本应该再次检查动画是否仍然有效。
另一个关于此类优化的教程(使用 Windows 工具)是WebReference 帧优化。请注意,该网站的名称有误,因为它实际上是关于压缩优化。

次要优化

GIF 动画可以使用一些其他的优化技巧,这些技巧通常非常明显,以至于被忽略了。
  • 移除 GIF 注释。
    许多 GIF 动画都添加了大量的文本注释。通常这些是由图形编辑器自动添加的,作为一种广告形式。例如,“Gimp”默认情况下会将“Created with The GIMP”添加到图像中。如果不需要注释,则它是空间浪费。通过在保存 GIF 之前,在 IM 的“magick”命令中添加“+set comment”操作符来移除它们。但是请注意,如果注释是版权声明,出于法律原因,最好不要移除它。
  • 减少颜色数量。
    如果动画在使用较少颜色时看起来还可以,请使用较小的颜色表。颜色表始终是 2 的幂,因此,如果您能够使用少于 32 种颜色,那么这比使用 256 种颜色要小得多。这尤其重要,因为颜色表不会被用于 GIF 图像数据的 LZW 压缩所压缩。此外,使用较少的颜色通常会产生更好的 LZW 压缩,因为会发现更多常见的像素序列。然而,情况并非总是如此,因为颜色抖动(由于颜色减少)也会使压缩效果变差。在此处关闭抖动或使用有序抖动可能非常重要。
  • 将用户可见帧的数量减半。
    如果您能够处理不太流畅的动画,那么将总帧数减半可以显著改善最终文件大小。当然,您不会得到大小减半的文件,并且动画质量也会降低。但它可以显著减少文件大小。
  • 裁剪/调整动画大小。
    较小的图像尺寸意味着较小的文件尺寸。因此,如果您不需要大型动画,请勿使用大型动画。在列表中,表示较大动画或视频的小型缩略图通常比实际内容更可取。
  • 替代压缩。
    如果您不打算将动画用作动画,即您只想存储它,请关闭 LZW 压缩,并“gzip”或“bzip2”压缩整个文件以进行存储!结果会小得多,尽管它需要 Web 服务器向浏览器提供正确的“内容”和“压缩”提示,以便客户端浏览器能够直接使用它。“Apache” Web 服务器默认情况下不会这样做,但可以配置使其执行此操作。更好的是,将整个未压缩动画目录归档到单个文件中,以获得更好的存储压缩。
如果您有任何其他优化想法,请告诉我。

有关 GIF 优化的其他信息来源

以上内容完成了处理动画的各种基本方法和技巧。但是,为了形成完整的画面。您应该继续进入下一个 IM 示例页面,详细介绍处理实际图像动画问题的技巧。此外,上述许多技巧都体现在视频到 GIF 优化的实际示例中。如果您真的认真对待 GIF 动画的处理,我还建议您彻底阅读有关颜色量化的内容,因为颜色减少通常是良好 GIF 动画处理的关键。我在 WWW 上发现的其他关于 GIF 动画优化技巧的有用来源包括……如果您认为我应该在此处列出某个页面,请给我发送邮件。我只会添加有用的内容页面,因此无法保证会添加您的链接。