ImageMagick 範例 --
動畫修改

索引
ImageMagick 範例 前言與索引
動畫的簡單修改
動畫 Alpha 合成
所有閃光...
調整動畫大小
合併多個動畫
此頁面包含處理 GIF 動畫的實用範例。強烈建議您在嘗試理解這些範例之前,先閱讀並理解 動畫基礎知識 以及至少 優化 GIF 動畫 的整體處理方式。

動畫的簡單修改

首先,一個重點

請勿將未完成處理的動畫中間檔案直接儲存為 GIF 格式,尤其是尚未執行任何半透明處理顏色最佳化的影像。如果您犯了將檔案儲存為 GIF 的大錯,您只會讓結果動畫變得更糟,因為 IM 現在會執行自動顏色量化,以減少存在的顏色數量,使影像符合有限的 GIF 格式。不僅如此,它還會將每一格與其他所有影格完全分開處理,產生不同的顏色選擇和抖動模式。也就是說,這會讓任何進一步的處理,尤其是任何影格最佳化變得更加困難。這對於調整大小的 GIF 動畫或已添加多色覆蓋或底層的動畫尤其重要,因為這可能會添加許多額外的顏色。如果您想逐步處理動畫或為每個正在編輯的影格使用單獨的 PNG 格式影像,則可以使用 IM 內部格式 MIFF 作為臨時檔案格式。除非您現在確定不會有顏色問題,否則請勿將最終檔案儲存為 GIF。我重複…
請勿使用 GIF 作為中間檔案格式,請使用 MIFF 或 PNG 影像。

註釋- 在所有影格上添加版權聲明

從 IM 6.2.6 版開始,您可以使用“-annotate”為動畫添加註釋,方法與在影像上添加註釋中詳述的方法類似,只需執行即可。例如,這裡我們註釋在動畫基礎中建立的上一個處置動畫

  magick canvas_prev.gif -gravity center \
          -fill black     -annotate +1+1 "Copyright" \
          -fill white     -annotate +0+0 "Copyright" \
          annotate.gif
  gif_anim_montage annotate.gif annotate_frames.gif
[IM Output]
[IM Output]
之所以可行,是因為“-annotate”會將文字相對於影像的虛擬畫布定位,而不是相對於實際影像資料定位。因此,文字在每一影格上的位置對於動畫影像是正確的。但是在 6.2.6 版之前,“-annotate”像許多其他影像運算子一樣,相對於實際影像定位資訊和覆蓋,並忽略子影格可能具有的任何頁面或虛擬畫布偏移。請注意,在沒有先合併動畫的情況下,像這樣在動畫上繪製可能會導致一些異常效果,因為存在動畫最佳化機制(請參閱下一組範例)。因此(正如您將看到的),建議先通過合併刪除任何現有的影格和透明度最佳化。

繪圖- 修改合併的動畫

現在,雖然“-annotate”會將文字放置在相對於每個影格的虛擬畫布的位置,但許多其他影像操作卻不會這樣做。這包括所有“-draw”操作,它們僅相對於實際影像繪製物件,並且完全忽略它在較大畫布上的任何偏移。例如,這裡我們在上一個處置動畫的左上角附近繪製一個花哨的綠色圓圈。

  magick canvas_prev.gif -fill LimeGreen -stroke SeaGreen \
          -draw 'circle 35,35 20,30'  draw_circle_fail.gif
  gif_anim_montage draw_circle_fail.gif draw_circle_fail_frames.gif
[IM Output]
[IM Output]
正如您所見,“-draw”相對於“實際影像”而不是影像所屬的較大虛擬(頁面)畫布繪製圓圈。結果就像這種情況下經常發生的那樣……一團糟。解決此問題的簡單方法是在繪製之前先合併動畫,然後再重新最佳化 GIF 動畫。有關詳細信息,請參閱最佳化動畫

  magick canvas_prev.gif -coalesce \
          -fill LimeGreen -stroke SeaGreen -draw 'circle 35,35 20,30' \
          -layers Optimize  draw_circle.gif
  gif_anim_montage draw_circle.gif draw_circle_frames.gif
[IM Output]
[IM Output]
請注意 IM 動畫優化器實際上決定不覆蓋已繪製的部分。這實際上比直接在子影格圖像本身上繪製更理想。此方法允許您疊加任何類型的註釋、版權聲明或浮水印。當然,您可能需要使用特殊的 圖層合成 技術將圖像疊加到動畫中的每一幀。如果您非常熟練,您甚至可以執行 動畫合併 來將動畫版權聲明疊加到您的動畫上。
雖然這種「合併優化」技術適用於大多數涉及動畫的操作,特別是使用 IM 的優化器時,但有些操作會對圖像進行劇烈的更改,例如重大的顏色更改、陰影和半透明效果,導致最終動畫無法很好地優化。

例如,幾乎任何 "-resize" 操作都可能產生在優化後效果不佳的動畫,因為顏色會發生重大變化。有關解決方案,請參閱下方的 調整動畫大小

逐幀處理- 一次修改一幀

通過使用 IM 圖像列表或序列運算符,您可以單獨修改動畫的每一幀。訣竅是在括號中提取每一幀,進行修改,然後用修改後的版本替換原始圖像。例如,我們在這裡將文字作為版權浮水印添加到動畫中,作為動畫本身,使其更難以刪除。為了不完全破壞動畫,我還使用了半透明顏色。

  magick canvas_prev.gif -coalesce -gravity center \
          -font Ravie -pointsize 24 -fill '#FFF8' -stroke '#0008' \
          \( -clone 0 -annotate 0 'This'        \) -swap 0 +delete \
          \( -clone 1 -annotate 0 'This'        \) -swap 1 +delete \
          \( -clone 2 -annotate 0 'image'       \) -swap 2 +delete \
          \( -clone 3 -annotate 0 'is'          \) -swap 3 +delete \
          \( -clone 4 -annotate 0 'Copy\nright' \) -swap 4 +delete \
          -layers OptimizeFrame   frame_mod.gif
  gif_anim_montage frame_mod.gif frame_mod_frames.gif
[IM Output]
[IM Output]
請注意 括號 的使用,將 "-annotate" 操作的效果限制為僅僅「複製」動畫的一幀。然後使用 交換刪除 運算符將修改後的圖像返回到圖像序列中的正確位置。
"-swap" 運算符中的單個數字用法已添加到 IM v6.3.4-3 中。在此之前,您需要將 "-swap 3" 指定為 "-swap -1,3" 才能使其正常工作。
這種修改單個幀的技術可能是您在處理圖像動畫時遇到的最重要的技術之一。您還會注意到,我實際上在第一個和第二個圖像中都添加了相同的文字。上述動畫中的第一個圖像是 零延遲中間幀,用於定義此動畫其餘部分的背景。也就是說,它閃爍得非常快,用戶通常看不到它,也不打算讓它可見。因此,上述動畫中的前兩個實際幀應被視為一個可見幀,而不是兩個單獨的幀。具有非零時間延遲的幀是「顯示」幀序列的最後一幀。同樣,對於其他快速運行的動畫,您可能需要修改多個幀才能使您的更改在任何可觀的時間內可見。對於繪製在所有幀上的靜態註釋來說,這不是問題(請參閱上面先前的 添加註釋 示例)。這就引出了一個關於 GIF 動畫的重要觀點。
在嘗試修改動畫之前,請先研究它。
它會對最終結果產生重大影響。

裁剪- 限制動畫區域

IM 一直致力於使 "-crop" 圖像操作相對於圖像虛擬畫布而不是實際圖像正確工作(IM 版本 6.1.1 及更高版本)。這反過來又允許您執行以前無法直接完成的操作。例如,裁剪 GIF 動畫的圖像,並使其按預期適用於所有動畫。

  magick canvas_prev.gif -crop 50x50+3+30  cropped.gif
  gif_anim_montage cropped.gif cropped_frames.gif
[IM Output]
[IM Output]
如您所見,裁切操作成功了,就像裁切單張圖片一樣,保留了適當的偏移量和頁面大小,因此即使涉及的區域已縮減,圖片資料仍然定位正確。如您所見,這並沒有改變整體虛擬畫布的大小!
不要使用「+repage」來移除已進行影格最佳化的 GIF 動畫的裁切偏移量。這樣做也會移除定位子影格在虛擬畫布上所需且後續影格可能依賴以正確製作動畫的影格偏移量。
不過,上述的「-crop」操作確實產生了一則警告訊息…
[IM Text]
由於動畫中其中一個影格的裁切遺漏了該影格使用的子影格覆蓋圖片,也就是有一個影格沒有更新從動畫中裁切的區域。因此,該影格現在不包含任何實際圖片!為了彌補這一點,IM 不僅會產生警告訊息,還會產生一個特殊的「遺漏圖片」作為動畫中的佔位符,以保持所有內容的順序,並保留附加到該影格的任何「延遲」或「處置」方法。您可以保留該佔位符,或根據需要進行修正。在這種情況下,「遺漏圖片」是動畫按預期運行所必需的。但是,如果產生多個連續的遺漏圖片,您可以使用「-layers」方法「RemoveDups」將它們合併成一個遺漏圖片。不過,仍然建議謹慎操作並仔細研究動畫。(有關更詳細的範例,請參閱下方「分割動畫」。

也裁切畫布- 動畫的視口裁切

就像一般的裁切會保留原始圖片的虛擬畫布一樣,裁切動畫也是如此。但在這種情況下,這可能不是預期結果。因此,在 IM 6.2.4-5 版中,「-crop」參數中新增了一個特殊的旗標「!」。此旗標會使裁切不僅裁切個別的圖片影格,還會將圖片的頁面或畫布資訊調整為相同的區域。這稱為「視口裁切」,因為結果就像您是透過大小和位置與裁切參數相同的「視窗」或「視口」來觀看圖片一樣。不僅虛擬畫布的大小會設定為裁切區域的大小,動畫中每個影格的偏移量也會進行調整以保持正確。(請參閱使用畫布/頁面調整進行視口裁切)。例如,讓我們重複先前的裁切,但這次也使用「!」旗標裁切畫布資訊…

  magick canvas_prev.gif -quiet -crop 50x50+3+30\!  crop_viewport.gif
  gif_anim_montage crop_viewport.gif crop_viewport_frames.gif
[IM Output]
[IM Output]
!」字元對某些 UNIX 殼層(例如「csh」)具有特殊意義,即使放在引號內也必須使用反斜線進行跳脫。IM 會忽略幾何參數中的反斜線,因此始終使用反斜線進行跳脫並沒有壞處。
您可以看到結果更像是您在裁剪動畫圖像時真正想要實現的。請注意,我包含了一個「-quiet」設定,要求 IM 不要發出關於遺漏圖像的警告訊息,這是我們在之前的裁剪嘗試中產生的。每當裁剪動畫時,建議這樣做,因為警告實際上並不適用。請注意,視口裁剪也允許您增加畫布區域,甚至重新定位畫布中的所有內容。但是,這很危險,因為任何部分或完全落在裁剪區域之外的圖像都將被裁剪,只顯示出現在該區域內的圖像部分。最後一句警告。當使用「視口裁剪」時,幀圖像會朝「視口」給定偏移量的負方向移動。這看起來可能不合邏輯,除非您記得裁剪運算符中的偏移量是視口的位置,而不是圖像本身的直接重新定位。

邊界修剪- 自動畫布尺寸校正

與之前的操作一樣,修剪動畫可能會很棘手。如果動畫由簡單的清除幀動畫組成,則您只需計算動畫中所有單獨幀的最大邊界即可修剪動畫。從 IM v6.3.4-8 開始,您可以使用「TrimBounds」圖層方法輕鬆完成此操作。

  magick anim_bgnd.gif -layers TrimBounds anim_trim_bounds.gif
[IM Output] ==> [IM Output]
對於此 IM 版本之前的用戶,您仍然可以執行相同的操作,但只能分兩步完成(這也會執行其他不必要的處理)。為此,您可以使用圖層合併將動畫的所有幀合併到單個圖層中,然後讓 IM 報告該圖層的大小和偏移量...

  magick anim_bgnd.gif -layers merge -format '%wx%h%X%Y' info:
[IM Text]
現在您知道了所有幀的邊界,您可以將整個動畫視口裁剪到此大小。

  magick anim_bgnd.gif -crop 89x77+5+10! anim_trim_crop.gif
[IM Output] ==> [IM Output]
如果您還想從動畫中修剪靜態背景,那麼最好的選擇是在使用圖層合併步驟之前,從幀優化動畫中刪除第一幀。然後,您可以將返回的邊界用於原始動畫上的視口裁剪

重新定位幀

一個類似且相關的操作是「相對重新分頁」運算符。這會將給定的偏移量添加到動畫的所有單獨子幀圖層中,允許您相對於整個畫布調整它們的位置。要使「-repage」操作相對,您還需要在其參數中添加一個「!」標誌。例如,在這裡,我們將動畫的第二幀和後續幀向下和向右移動 30 個像素,將第一個「背景」幀返回到其正常的「+0+0」位置。

  magick canvas_prev.gif -repage 0x0+30+30\! \
           \( -clone 0 -repage +0+0 \) -swap 0,-1 +delete \
           repage_offset.gif

  magick identify repage_offset.gif
[IM Output]
[IM Text]
對於 Windows Internet Explorer 版本 8,上述動畫將失敗(僅顯示前兩幀)。每當幀嘗試繪製超出動畫畫布邊界的圖像時,就會發生這種情況。
請注意,沒有任何圖像被「裁剪」或裁切。只有它們的位置相對於原始背景圖像發生了變化,即使圖像被移動到「畫布外」。
如果您願意,您也可以擴展畫布以匹配這些新邊界,方法是直接調整畫布大小...

  magick repage_offset.gif -repage 130x130  repage_canvas.gif
[IM Output]
通過使用邊界修剪圖層方法,您可以自動擴展動畫邊界,使其足以包含現在放置在「邊界外」的圖像...

  magick repage_offset.gif -layers TrimBounds repage_bounds.gif
[IM Output]
使用「-repage」向左或向上移動圖像,尤其是在畫布較小的情況下,對於 GIF 動畫很可能會失敗。此格式基本上不能使用負圖像偏移量。

為此,您最好也應用「視口裁剪」,或使用「修剪邊界」將所有偏移量轉移到更大的正畫布中。無論哪種方法都可以保證所有圖像幀都有正偏移量。

PNG 和 MNG 格式可以處理負偏移量,但許多網路瀏覽器和其他程式可能無法理解此類偏移量,從而產生奇怪的效果。例如,一個版本的「Firefox」網路瀏覽器在嘗試顯示帶有負偏移量的 PNG 時會產生極大的圖像。

反轉動畫- 使動畫倒退或循環

從 IM v6.3.3 開始,添加了「-reverse」圖像序列運算符(有關更多詳細信息,請參閱反轉運算符)。這使您可以非常輕鬆地反轉合併動畫序列的順序。例如,在這裡,我製作了一個「手繪 k」動畫變成未繪製的!

  magick script_k.gif -coalesce -reverse \
          -quiet -layers OptimizePlus  -loop 0 reversed.gif
[IM Output]
我必須將「-loop」選項重新添加到上述內容中,因為這需要附加到第一張圖像,現在是最後一張圖像!結果可能還需要進行一些時間調整,但正如您現在所見,它現在「取消繪製」了字母!請務必在反轉圖像序列之前「-coalesce」它,因為存在的任何幀優化都取決於圖像順序。最好先刪除這些優化。

巡邏週期- 在兩端之間來回循環

一種類似的技術是將反向幀順序添加到動畫的末尾,以便生成的動畫在原始動畫的第一幀和最後一幀之間循環。這有點像警衛在兩點之間巡邏,稱為「巡邏週期」。在這裡,我使用圖像複製運算符(添加到 IM v6.6.8-7)來生成額外的幀(反轉)。

  magick script_k.gif -coalesce   -duplicate 1,-2-1 \
          -quiet -layers OptimizePlus  -loop 0 patrol_cycle.gif
[IM Output]
請注意,我不僅複製了動畫的所有圖像,還跳過了複製原始序列的第一張和最後一張圖像。如果我複製了所有圖像,則第一張和最後一張圖像將顯示預期時間的兩倍,並使動畫文件大於所需的大小。儘管如此,您應該再次注意動畫開始和結束處的零延遲中間幀,因為這些可能會導致意外問題。基本上,在不先研究動畫的情況下不要這樣做,否則就是在自找麻煩。此外,為了更好地優化結果,您甚至可能需要在正向和反向循環之間添加一些額外的零延遲中間幀,以改進優化。原始動畫優化中可能沒有提供這些額外的幀,因為整個動畫通常在循環時重置。有關這些額外幀如何幫助優化和改進動畫的更多詳細信息,請參閱拆分幀更新。這是一種使用克隆運算符生成重複幀的舊方法。

  magick script_k.gif -coalesce \( -clone -2-1 \) \
          -quiet -layers OptimizePlus  -loop 0 patrol_cycle_2.gif
[IM Output]

顏色變形- 兩個圖像之間的動畫變化

-morph」運算符是一個特別有趣的運算符。它將獲取圖像列表,並在它們之間插入額外的幀,以便進行從一張圖像到下一張圖像的柔和顏色變化。但是,此運算符不是真正的「變形」,因為它只會修改像素顏色,從而創建一系列混合圖像。真正的電影,如「變形」,還涉及圖像失真,以將圖像中對象的輪廓轉換為另一個圖像中的對象。例如,在這裡,我使用顏色變形創建一個巡邏週期,以在玫瑰圖像及其翻轉形式之間生成額外的幀。

  magick -delay 20 rose: \( +clone -flip \)  -morph 5 \
          -duplicate 1,-2-1  rose_flip.gif
[IM Output]
這種做法並不是很好,因為所有影像都有相同的延遲時間。結果就是動畫在循環的兩個端點之間永遠不會「靜止」或暫停。一個比較好的解決方案是在原始影像和其「翻轉」形式之間加入暫停。然而,這需要您調整原始影像的延遲時間,使其與變形影像的延遲時間不同。

  magick rose: \( +clone -flip \)  -morph 5 -set delay 10 \
          \( -clone 0 -set delay 240 \) -swap 0 +delete \
          \( +clone   -set delay 240 \) +swap   +delete \
          -duplicate 1,-2-1 rose_flip_pause.gif
[IM Output]
如您所見,計時延遲對於產生良好的動畫非常重要,它允許動畫在適當的時間點「靜止」。從 IM v6.6.9 版開始,您可以使用根據影像索引計算的 FX 百分比跳脫字元 來設定延遲時間。這裡的 FX 運算式表示,如果影像索引不是第一個 (t=0) 或最後一個 (t=n-1),則使用 10 的延遲時間,否則使用較大的值。

  magick rose: \( +clone -flip \)  -morph 5 \
          -set delay '%[fx:(t>0&&t<n-1)?10:240]' \
          -duplicate 1,-2-1    rose_flip_anim.gif
[IM Output]
如需各種「變形」或在兩個影像之間進行「轉場」的方法,請參閱 Fred Weinhaus 的「transitions」和「fxtransitions」ImageMagick 殼層腳本。範例頁面包含腳本用於產生動畫的基本演算法。

調整大小變形- 動態改變大小

色彩變形運算子 實際上不僅可以在兩個影像之間進行色彩混合,還可以同時調整影像大小。例如,我在這裡對兩個大小不同、甚至長寬比不同的影像使用「-morph」。

  magick rose: medical.gif -morph 10 \
          -layers TrimBounds -set dispose previous -coalesce \
          -background black -alpha remove \
          -set delay '%[fx:(t>0&&t<n-1)?10:60]' \
          -duplicate 1,-2-1  -loop 0  morph_resize.gif
[IM Output]
只有第一行會執行調整大小變形。如果您要查看實際的影像,會發現每個影格的大小都不同!接下來的兩行會將影像「填滿」到相同的大小,並用黑色填充未使用的部分。具體來說,這些運算是設計成與影像的順序無關。其餘部分只是設定 巡邏循環 和相關的計時延遲。'resize' 只會從左上角執行。在撰寫本文時,色彩變形運算子 不支援圖層偏移或任何其他空間變形(扭曲變形)。因此,如果您希望調整大小以中心為基準,則可能需要使用後續章節中顯示的更複雜技術。以下是一個類似的範例,這次是使用相同影像的較小版本(保留長寬比)來調整影像大小...

  magick rose: \( +clone -resize 10 \) -morph 10 \
          -layers TrimBounds -set dispose previous -coalesce \
          -background black -alpha remove \
          -set delay '%[fx:(t>0&&t<n-1)?10:60]' \
          -duplicate 1,-2-1  -loop 0  morph_resize_self.gif
[IM Output]
請注意,「中間」影像比預期的更模糊。這是因為較大的影像不僅被調整為較小的尺寸,而且還與被調整為較大尺寸的較小影像進行了色彩混合。

擦拭- 從一個影像到另一個影像建立擦拭效果

這實際上很容易做到。只要覆蓋新影像的「條狀」即可。這些條狀可以使用簡單的 平鋪裁剪 直接產生。例如,我們在這裡從一個影像「擦拭」到其翻轉版本,並且為了好玩,再擦拭回來。

  magick rose: \( -clone 0 -flip -crop 3x0 \) \
                \( -clone 0 -crop 3x0 \) \
                -set delay 10 -loop 0  wipe.gif
[IM Output]
以下是由 GeeMack 在 IM 論壇上提供的版本,它可以從四個方向執行擦拭...

  magick -size 100x60 -delay 100 \
      gradient:green-yellow gradient:blue-purple \
      gradient:orange-white gradient:red-black \
      -write mpr:stack -delete 0--1 \
      \
      mpr:stack'[0]' \( mpr:stack'[1]' -set delay 5 -crop 4x0 \) \
      mpr:stack'[1]' \( mpr:stack'[2]' -set delay 5 -crop 0x4 \) \
      mpr:stack'[2]' \( mpr:stack'[3]' -set delay 5 -crop 4x0 -reverse \) \
      mpr:stack'[3]' \( mpr:stack'[0]' -set delay 5 -crop 0x4 -reverse \) \
      -loop 0 wipe_all.gif
[IM Output]

動畫扭曲- 根據影像索引扭曲多個影像

許多運算子可以在其引數中使用 百分比跳脫字元。這表示您可以實際修改運算子,使其針對正在處理的每個影像執行略有不同的操作。該方法涉及首先 複製影像 以建立玫瑰影像的 30 個(或任意多個)相同副本。然後,您可以使用 FX 百分比跳脫字元 根據影像索引 '%[fx:t]' 和清單中的影像數量 '%[fx:n]' 計算扭曲值,從而以不同的方式修改每個影像。例如,我在這裡根據計算出的數量平移影像。

  magick rose: -duplicate 29  -virtual-pixel tile \
          -distort SRT '0,0 1, 0, %[fx:w*t/n],%[fx:h*t/n]' \
          -set delay 10 -loop 0     rose_diagonal_roll.gif
[IM Output]
在這裡,我會根據索引旋轉影像,但如果影像索引為 0(第一個影像),則會產生較長的暫停。

  magick rose: -duplicate 29  -virtual-pixel Gray \
          -distort SRT '%[fx:360*t/n]' \
          -set delay '%[fx:t==0?240:10]' -loop 0     rose_rotate.gif
[IM Output]
請注意,圖像索引(「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」在其中添加一些文字。

  magick canvas_prev.gif \
          \( -clone 0 -coalesce -gravity South -background white \
             -splice 0x18 -annotate 0 'Label First' \) \
          -swap -1,0 +delete   label_first.gif
[IM Output]
但是,這僅適用於某些動畫,它不適用於常見的「清除幀動畫」,後者在顯示每一幀後清除或替換所有像素。對於適用於所有動畫的更通用的方法,我們需要先將動畫「-coalesce」到未最佳化的「合併動畫」。然後,我們可以在重新最佳化之前將標籤添加到動畫的每一幀合併幀中。

  magick canvas_prev.gif -coalesce \
          -gravity South -background white -splice 0x18 \
          -annotate 0 'A Better Label' \
          -layers Optimize labeled_anim.gif
[IM Output]
您可以使用合成方法(請參閱下一節)將圖像合成到添加的空間中,而不是使用「-annotate」在添加的空間中繪製文字。這樣,您可以準備一個更漂亮的標籤來添加到動畫中。當然,這樣做可能會導致某些動畫之後無法很好地最佳化,尤其是「清除幀動畫」,但這是您添加標籤所付出的代價。對於這種類型的動畫,一種解決方案是預先設置一個包含標籤的「初始背景畫布」,如說明「清除幀動畫」的部分所示。另請注意,向動畫添加標籤可能會導致添加許多額外的顏色。這可能會超過 GIF 顏色限制,因此您可能還必須準備好對動畫進行顏色最佳化。如果可能,最好避免這項非常困難的任務(請參閱「顏色最佳化」)。對於任何動畫的任何一般修改,這都可能是一個問題。

移除透明度- 添加純色背景

您在網路上看到的很多動畫都有透明背景。這些都非常有用,因為您可以將它們放在網頁上,而不必擔心可能出現的任何背景圖案。然而,在處理動畫時,尤其是在應用其他影像運算子(如「-resize」和「-blur」)時,此類動畫會出現問題。一般的解決方案是從影像中移除透明度,通常是透過某種方式將它們疊加到特定顏色上,例如用作網頁背景的特定顏色。 [IM 輸出] 例如,這裡有一個簡單的透明疊加動畫,字母「K」就像被一隻看不見的手畫出來一樣。由於此 GIF 動畫是用透明度繪製的,並且僅將影像疊加到前一幀上(添加像素,從不移除它們),因此設定背景顏色(或影像)的簡單方法是僅將其添加到動畫的第一幀。所有其他幀都包含背景的透明顏色,因此不會影響結果。在這裡,我們使用平面化運算子將動畫的第一幀疊加到「LimeGreen」背景顏色上。我們可以使用「-flatten」來實現此目的,因為我們僅將其應用於單個影像,而不是整個動畫。

  magick script_k.gif \( -clone 0 -background LimeGreen -flatten \) \
          -swap 0,-1 +delete      script_k_flatten_0.gif
[IM Output]
同樣重要的是要注意,原始的第一幀只是一個像素大小。平面化運算子不僅為背景著色,還將該幀擴展到其完整大小。也就是說,它也「填充」了框架。但是請注意,因為只有動畫的第一幀被著色了。這種方法是首選的,因為任何優化(例如此動畫包含的繁重優化)都將保留。為第一幀著色並不適用於所有 GIF 動畫。它僅適用於簡單的疊加動畫。要使用通用的方法從動畫中移除透明度,您需要先對動畫「-coalesce」,然後使用Alpha 移除運算子實際從所有幀中移除透明度。這次讓我們使用「Tomato」背景顏色來做到這一點。

  magick script_k.gif -coalesce   -background Tomato -alpha remove \
          -layers Optimize   script_k_alpha_rm.gif
[IM Output]
當然,最終的優化可能不如原始的那麼理想,但動畫中不再有任何透明度。作為一個額外的副作用,動畫中的任何「背景」處置設定都將透過幀優化過程轉換為「」或「先前」,因為透明度不再是一個問題。
Alpha 移除已添加到 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 的用戶。
例如,在這裡我將玫瑰圖像疊加在整個動畫上。

  magick canvas_prev.gif -coalesce \
          -gravity NorthEast  -draw 'image over 5,5 0,0 "rose:"' \
          -layers Optimize   draw_over.gif
[IM Output]
這使您可以將外部 *來源* 圖像 合成 到當前圖像序列中的每個圖像上。這對於大多數目的來說已經足夠了。例如,通過使用 'Dst_Over' 合成方法,您也可以將圖像作為靜態背景放置在動畫“下方”。例如,在這裡我們“襯底”了一個“netscape:”內置圖像,儘管它可以是任何外部圖像文件...

  magick script_k.gif -coalesce \
              -draw 'image DstOver 0,0 0,0 "netscape:"' \
          -layers Optimize   script_k_netscape.gif
[IM Output]
請注意,動畫的大小沒有改變,因為 *目標* 圖像定義了 Alpha 合成的最終大小。如果您確實想創建更大的畫布,則必須適當地調整動畫的大小和偏移量以適應背景。例如,在合併之前使用動畫的 相對重新分頁

  magick script_k.gif  -repage 100x100+20+20\!   -coalesce \
              -draw 'image DstOver 0,0 0,0 "granite:"' \
          -layers Optimize   script_k_granite.gif
[IM Output]
此外,如果您想使用已讀取、創建或修改的圖像,則需要使用“MPR:內存程序寄存器”來為您提供該圖像的“讀取來源”。

  magick -size 53x54 xc:SkyBlue -fill DodgerBlue \
          -draw 'circle 26,27 24,8' -write mpr:bgnd +delete \
          \
          script_k.gif -coalesce \
          -draw 'image DstOver 0,0 0,0 "mpr:bgnd"' \
          -layers Optimize   script_k_mpr_bg.gif
[IM Output]
也就是說,關於繪製 Alpha 合成方法的限制。沒有將動畫圖像疊加到未知大小的 *目標* 圖像“之上”,也沒有辦法將兩個獨立的多圖像序列合併在一起。直到...

圖層合成- 圖像列表的 Alpha 合成

在 IM v6.3.3-7 中,添加了“-layers”方法“'Composite'”,允許您將兩個完全獨立的圖像集合成在一起。(有關簡要概述,請參閱 圖層化圖像、圖層合成)要在命令行上執行此操作,需要一個特殊的“null:”標記圖像來定義第一個 *目標* 圖像列表的結束位置和疊加的 *來源* 圖像列表的開始位置。但這是此方法唯一真正的複雜之處。讓我們嘗試通過從一組圖像創建一組陰影,然後將原始圖像疊加到這些陰影圖像上来嘗試一下...

  magick script_k.gif -coalesce  coalesced_k.gif

  magick coalesced_k.gif  -background black -shadow 100x3+2+5 \
          -background SkyBlue -alpha remove    shadows_k.gif

  magick shadows_k.gif  null:  coalesced_k.gif \
          -layers Composite          compose_shadow.gif

  gif_anim_montage compose_shadow.gif compose_shadow_frames.gif
[IM Output]
[IM Output]
[IM Output]
[IM Output]
上述範例非常重要,因此我會詳細說明。首先,我們會產生動畫的合併版本,以移除任何可能存在的最佳化,讓動畫在進行任何嚴肅的處理之前做好準備,而不會受到任何 GIF 最佳化的干擾。接下來,我們從合併的動畫建立一個動畫陰影圖像,並移除透明度,因為 GIF 無法處理半透明陰影。這就是我們想要添加到原始動畫「下方」的動畫。它具有與原始動畫相同的影格數,甚至相同的時間。這種對應關係很重要,請不要忘記。現在我們讀取兩個動畫或圖層序列,但在它們之間添加一個特殊的「null:」圖像分隔符號,以便 ImageMagick 知道一個序列何時結束以及下一個序列何時開始。此圖像分隔符號會被下一個非常重要的「-layer composite」操作自動移除。其他 API 應該能夠使用單獨的圖像「Wands」,而不是使用帶有特殊分隔符號的單一序列。然後,圖層合成就像這兩個動畫或圖像序列只是一個簡單的單一圖像一樣執行,而不是多個圖像的序列。每對圖像(一個目標圖像和一個來源圖像)會被合成在一起,以生成圖像的合併(合成)序列。最終結果是我們在原始動畫序列中添加了陰影,可以進行 GIF 最佳化,或者直接使用。
現在,您可以使用單一指令完成上述所有步驟。但是,您不能僅使用「-clone」來建立原始序列的副本,因為我們並不真正知道(或想知道)序列中有多少個圖像。相反,您可以使用「MPR:記憶體程式暫存器」來儲存整個圖像清單。這有點像對當前記憶體中的整個圖像序列進行快照,然後稍後再讀取它。結果是像這樣的指令,不過我使用了不同的背景顏色。

  magick script_k.gif -coalesce -write mpr:images \
          -background black  -shadow 100x3+2+5 \
          -bordercolor Wheat -border 0 \
          null:    mpr:images    -layers Composite \
          magick composite_shadow.gif
[IM Output]
這個版本實際上效果更好,因為我們沒有遺失陰影運算符產生的偏移資訊(GIF 無法儲存負偏移,因此將其重置為零)。我們可以在上面透過對中間圖像使用 MIFF 檔案格式而不是 GIF 來解決這個問題,或者,正如您在下一個範例中將看到的,透過使用「-geometry」合成偏移。基本上,這些範例表明圖層合成運算符實際上理解個別的虛擬畫布偏移(「-page」)設定,並且會像圖層平面化或更好的圖層合併運算符一樣處理它們。但是圖層合成運算符也理解合成幾何(「-geometry」)偏移(預設值為零)的使用,以控制整個覆蓋圖像序列的整體位置。它甚至理解「-gravity」對該全域偏移的影響。例如.. 讓我們將原始的「K」動畫覆蓋在生成的陰影動畫的「下方」...

  magick shadows_k.gif  null:  coalesced_k.gif  \
          -geometry +0-10 -gravity South  -layers Composite \
          magick composite_south.gif
[IM Output]
上面還表明,就像普通的兩個圖像Alpha 合成一樣,控制最終輸出圖像大小的是目標圖像序列,並且任何合成覆蓋都將被裁剪到目標畫布圖像。因此,您應該確保所有目標圖像都足夠大,以包含最終結果。
-geometry」的調整大小功能嚴格來說不是合成操作的一部分,它只調整當前圖像序列中最後一個圖像的大小。因此,如果與多圖像圖層合成一起使用,它將不會達到您的預期效果。有關詳細資訊,請參閱調整幾何大小
基本上,圖層合成與一般合成非常相似。
真的非常簡單。我有說很簡單嗎?
圖層合成細節......如您在上方所見,「-layers Composite」的命令列版本使用在目前影像清單中找到的第一個「null:」影像作為標記,以分隔兩個清單。這兩個影像清單會被分開,並且在兩個清單被Alpha 合成在一起(一次兩個影像)之前,「null:」會被丟棄。只有從特殊的「null:」影像來源產生的影像才能用於標記,如果找不到,則會回報錯誤。您目前無法從管道讀取這個「null:」標記影像(至少目前還不行),只能在需要時產生它。圖層合成也比簡單的兩個影像Alpha 合成複雜得多,因為也會考慮到影像清單的影像虛擬畫布。一般來說,Alpha 合成會忽略任何虛擬畫布大小和用於定位的偏移量,只使用影像的實際大小。這種特殊的圖層方法使用虛擬畫布資訊來進行幾何定位,以便對齊兩個影像序列。為此,子影格具有的任何虛擬畫布偏移量也會添加到正常的「-gravity」調整的「-geometry」合成偏移量中,以計算出影像覆蓋的位置。只有每個清單中第一個影像的虛擬「-page」畫布大小會用於計算「-gravity」對「-geometry」合成偏移量的調整。換句話說,「-layers Composite」是用於「圖層」或「動畫」的 Alpha 合成,以及此類影像清單的特殊需求。注意事項...不過,您仍然需要注意要覆蓋的影像清單。例如,如果目標清單影像不夠大,或者定位不正確而無法容納覆蓋的來源影像,則覆蓋的影像將被裁剪,或者完全錯過目標影像。因此,最好在覆蓋較小的來源影像之前,將目標影像合併到完整的畫布大小。例如,請參閱下面的依大小並排動畫附加範例,其中需要擴展畫布大小以提供附加影像的空間。此外,如果來源影像清單是 GIF 動畫,則您可能需要確保子影格中沒有以下內容:壓縮最佳化和花俏的影格最佳化;否則您可能會遇到問題。另一方面,清除的影格動畫合併的動畫可以直接「Composite」,而不會有任何問題。請記住,圖層合成無法理解影像中可能存在的任何現有GIF 處置方法,儘管它會保留目標GIF 動畫中繼資料,例如:處置方法影格延遲迭代迴圈限制。這個規則的一個例外情況在下面的特殊情況中給出。

單一影像合成- 使用單一影像合成影像

通常來說,兩個長度相等的影像列表會被組合在一起,每次一對影像,直到其中一個影像列表用完為止。兩個影像列表都不會被重複使用。組合過程會在其中一個列表用完時停止。您最終會得到原始的*目標*影像列表,其中包含已添加的組合影像。 `null:` 分隔影像和所有*來源*影像都會從目前的影像列表中刪除。
這個圖層方法的 API 介面應該允許您產生兩個獨立的影像列表,並且由您自行刪除用於產生結果影像列表的兩個輸入影像列表。 `null:` 分隔影像應該不需要。
但是,如果其中一個列表只包含單一影像,則該影像將會與另一個列表中的所有影像進行合成。單一影像是*來源*影像還是*目標*影像是沒有區別的。此方法將會對另一個影像列表執行合成,並保留*影像列表*的 GIF 中繼資料,而不是單一影像的中繼資料,即使該影像為*目標*影像也是如此。這種「與單一影像合成」是圖層合成的一個特殊情況,對於為動畫添加背景(見下文)或將靜態物件插入動畫非常有用。

靜態背景- 合成到更大的背景上

例如,使用這種特殊的單一影像圖層合成方法,我們可以將動畫合成到靜態背景上...


magick -size 100x100 plasma:fractal null: \( script_k.gif -coalesce \) \ -gravity Center -layers Composite \ -layers Optimize magick composite_background.gif
[IM Output]
由於背景影像是*目標*,因此它定義了動畫的最終大小,但所有中繼資料(延遲、標籤、註釋等)都將來自來源影像列表。通常,這些資訊來自目標影像列表。這是影像合成期間唯一一次由來源影像提供中繼資料資訊。另請注意,由於圖層合成理解「-gravity」,因此影像會被正確置中,而無需您自行計算。但是,如果來源影格包含偏移量,這些偏移量也會被添加到重力定義的位置,以便所有子影格的相對位置保持正確。請注意,由於動畫「script_k.gif」實際上是一種覆蓋動畫,因此還有其他方法可以為動畫添加靜態背景。有關示例,請參見上文關於移除透明度的章節(到純色上,但可以是任何影像)。更簡單的已清除影格動畫也是如此。在這種情況下,您甚至不需要先合併動畫,而是可以直接將其合成到背景影像上。但是,您可能需要「-set」之後使用的「dispose」方法,或者更好地最佳化完全合併動畫。但是,任何其他類型的最佳化動畫都需要「-coalesce」操作,以及與所有動畫影格的完整合成。因此,最好使用上述方法,以確保所有 GIF 動畫都能正確處理。

閃閃發光的一切...

閃光動畫

以上 圖層合成 方法讓產生簡單動畫(例如閃光)變得容易許多。首先,我們需要一些夠大的閃光來覆蓋正在處理的影像。在這裡,我將使用一些 隨機斑點影像 來產生一個三影像閃光動畫。首先,這是純透明度上的原始黑白閃光,透過將三個顏色通道分離成黑白 通道影像 來產生三個閃光影格。它基本上是產生任何其他類型閃光的原始起點。「30%」閾值控制每個影格有多少「點」。


magick -size 100x100 xc: +noise Random -separate \ null: \( xc: +noise Random -separate -threshold 30% -negate \) \ -compose CopyOpacity -layers composite \ -set dispose background -set delay 20 -loop 0 glitter_overlay.gif
[IM Output]
透過這種「原始」閃光,您可以使用「螢幕」alpha 合成來覆蓋它,僅照亮某些顏色,以產生特定顏色的閃光。我使用 邊框扁平化方法(上方)。僅僅是一種純色...

  magick glitter_overlay.gif \
          -compose Screen -bordercolor GoldenRod -border 0x0  glitter_gold.gif
[IM Output]
使用 圖層合成,您也可以使用單個影像,甚至多個影像來提供可變的彩色背景。例如,在這裡我產生了三個 分形電漿 影像,為閃光圖案提供稍微隨機化的著色。


magick glitter_overlay.gif null: -size 100x100 \ plasma:red-firebrick plasma:red-firebrick plasma:red-firebrick \ -compose Screen -layers composite glitter_plasma.gif
[IM Output]
當然,還有很多其他的閃光風格和運動模式。您可以在網路上找到並下載許多此類閃光素材。要將這樣的閃光應用於影像,有許多不同的方法。通常,您會將閃光遮罩到特定的形狀或背景。為此,可以使用透明形狀(使用 DstIn 合成)

  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] ==> [IM Output]
或黑白遮罩影像(使用 CopyOpacity 合成)

  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] ==> [IM Output]
好的,我們有一個已經被遮罩的區域,您可以完成影像,通常是透過將遮罩的閃光覆蓋在原始影像上。但是,在我們的例子中,我會在下方放置一個背景,並在上方覆蓋一個邊框。

  magick glitter_masked.gif -size 100x100 \
          null: gradient:gold1-gold4 -compose DstOver -layers composite \
          null: \( -fill none -background none -stroke white -strokewidth 2 \
                   -font Candice -gravity center -pointsize 90 label:A \) \
              -compose over -layers composite      glittered_letter.gif
[IM Output]
最後一個例子還透過移除最終影像中的所有透明度並在閃光區域周圍覆蓋平滑邊框來清理任何 GIF 透明度問題。
雖然我可能在上面使用了 GIF 格式的影像,以便讓我可以神奇地顯示過程中的各個步驟,但在實務中,您要么將所有步驟組合成一個命令,要么使用更好的中間影像檔案格式,例如 MIFF。也就是說,這樣做是為了避免 GIF 格式的固有問題,直到我們完成。

閃光素材- 「影像中的孔洞」襯底

如前所述,網路上有很多預先準備好的動畫閃光素材影像(搜尋「閃光素材」)。一個來源是 IM Studio 的用戶 scri8e 和他的網站 Moons Stars。但是請注意,我發現大多數閃光素材看起來都很糟糕,或者速度太快。 在這個例子中,我找到並修改了一個帶有一些小星星圖案的藍色閃光素材。我認為它可以用來給 IM 巫師一件閃閃發光的衣服,讓他看起來真的很神奇。讓現有影像閃光的可能是最簡單的方法是在影像中剪出孔洞,而不是試圖遮罩閃光圖案。然而,這僅適用於一開始就不包含透明度的影像。或者,您可以從影像中移除透明度,並在完成後重新新增原始透明度。所以讓我們以 IM Examples 標誌為例,並使用 顏色替換 來剪切影像中的所有藍色部分。有點像給我們的巫師一件隱形斗篷 ;-)

  magick logo.gif -alpha set -fuzz 33% -transparent blue logo_holed.gif
[IM Output] ==> [IM Output]
請注意使用模糊因素來調整要移除多少藍色。但請注意,這不是從圖像中裁剪區域的好方法,因為它會產生鋸齒邊緣。但目前還沒有簡單的羽化裁剪功能。好的,我們現在有一張有孔洞(或許多孔洞)的圖像。下一步是在下面放置閃光磚圖像。問題是上面的磚塊太小了,它無法覆蓋整個圖像!
以下使用一種巧妙的技術來平鋪多圖像閃光磚。但是,您仍然需要提供大於原始圖像的尺寸,以確保可以完全覆蓋它。

  magick glitter_blue.gif -virtual-pixel tile \
          -set option:distort:viewport 180x180 -distort SRT 0 \
          glitter_blue_tiled.gif
[IM Output]
現在,讓我們通過將上述平鋪的閃光放在「有孔洞的」圖像下方,為我們的巫師穿上他的新衣服。

  magick logo_holed.gif null: glitter_blue_tiled.gif \
          -compose DstOver -layers composite \
          -loop 0 -layers Optimize logo_glittered.gif
[IM Output]
您當然可以在一個命令中完成所有這些步驟。在這裡,我將孔洞的生成限制在巫師斗篷上,它有兩個獨立的特定部分。

  magick logo.gif -alpha set -fuzz 10% -fill none \
          -draw 'matte 120,150 floodfill  matte 150,120 floodfill' \
          null: \( glitter_blue.gif -virtual-pixel tile \
            -set option:distort:viewport 300x300 -distort SRT 0 \) \
          -compose DstOver -layers composite \
          -loop 0 -layers Optimize logo_glitter_cloak.gif
[IM Output]
上面孔洞的創建使用了遮罩填充繪製基元,從圖像中選擇一個實際的點和顏色進行顏色替換。這意味著我不需要像最初那樣使用這麼高的模糊因素,因為我的比較顏色來自所選定的特定區域。此外,我使用了更大的平鋪「視口」,以確保完全覆蓋正在平鋪的圖像,而無需知道其確切尺寸。
通用扭曲運算符及其特殊的「viewport」選項(添加到 IM 6.3.6-0 中)的使用,也讓您有機會以其他特殊方式修改扭曲模式。例如,賦予它「透視」外觀或將圖案旋轉到非矩形角度。這樣做可以增強平鋪效果,使其看起來不那麼單調。

有關一些示例,請參見仿射平鋪

閃耀- 疊加大部分透明的閃光

前兩種閃光動畫技術的主要問題是它是一種全有或全無的替換類型。您無法使用圖像的原始陰影或背景。此外,閃光完全限於被遮罩的區域。它不能超出所涉及區域的範圍。因此,一些小區域,例如前面例子中的巫師「帽子」,處理閃光的效果並不好。閃耀是不同的,因為添加的動畫大部分是透明的。因此,原始圖像仍然可以顯示出來。通常以兩種方式之一將此類動畫添加到圖像中。動畫疊加層本身是透明的,或者它是黑色背景的形式,其中圖像應該變亮的地方有白色「火花」。
施工中
這是一個幾乎完全透明的「閃光」疊加層的例子。例子在這裡 如您所見,當使用此格式時,您可以擁有彩色閃光疊加層。這樣做的主要問題是使用 GIF 動畫來保存它(通常是這種情況),因此疊加層嚴重鋸齒狀。也就是說,它不能包含任何半透明像素來平滑疊加圖像的外觀。如果這樣做,您最終會在「閃光」周圍得到可怕的黑色光暈。讓我們將其遮罩並疊加到精靈上。例子在這裡 另一種形式的閃光是黑色背景上的白色閃光(灰度圖像)。這些被遮罩和覆蓋,以便使圖像變亮以添加閃光。例如... 例子在這裡 閃光最好的地方之一是您可以生成一系列幀,其中閃光緩慢出現然後消失。這可能會變得非常複雜,但做起來並不難。例子在這裡

新增光暈和星光動畫

閃光由單個亮點組成,而火花可以覆蓋圖像的某些區域,而光暈通常是單獨添加的。「光暈」基本上是一個閃爍的點,在短時間內覆蓋一大片區域。「星光」與此類似,只是覆蓋範圍更多地採用「光線」的形式。這些通常從特定的點「播種」,但結果通常至少會暫時超出播種區域。例如,僅限於特定區域的遮罩光暈看起來非常非常愚蠢和不自然。光暈更困難的方面是找到好的「種子」點和適當計時多個光暈。
施工中
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」會出現問題,無論是每幀的顏色數量,還是半透明的顏色。例如,這會變得非常糟糕...

  magick script_k.gif -resize 20x20 script_k_direct.gif
[IM Output]
==> [IM Output]
現在效果不太好,這是因為原始圖像進行了大量的幀優化。動畫的每個「幀」大小都不相同,「-resize」會將每個幀圖像與其他圖像完全分開調整大小。也就是說,上述操作調整的是實際幀圖像的大小,而不是動畫虛擬畫布的大小。實際上,我很驚訝結果動畫沒有比顯示的空白區域更「瘋狂」。這就引出了調整動畫大小的第一點。首先,確保所有幀都被完整定義,並且**已移除所有**優化。換句話說,在嘗試調整動畫大小之前,先合併動畫。例如...

  magick script_k.gif -coalesce  -resize 20x20  script_k_direct2.gif
[IM Output]
==> [IM Output]
下一個問題是透明度顏色。如果您查看上面的結果,您會發現較小動畫的邊緣出現嚴重鋸齒(「階梯狀」)。這是因為 GIF 無法保存「-resize」運算符生成的半透明顏色。動畫對象內的顏色也會合併在一起產生新的顏色,但这通常不如边缘鋸齒那麼糟糕。

使用平面化調整大小,一種通用的解決方案。

生成 GIF 縮略圖的最佳方法是完全避免透明度問題。也就是說,在調整動畫大小之前或之後平面化動畫。這樣,您就不會丟失調整大小圖像中邊緣的「抗鋸齒」效果。事實上,我發現大多數優秀的 GIF 動畫網站生成 GIF 動畫縮略圖時正是這樣做的。當然,縮略圖將被限制在特定的顏色背景上使用,通常是「白色」,有時是「黑色」或「銀色」(網頁灰色),儘管後者現在不太常見了。例如,我在這裡創建一個適合此網頁背景顏色的較小縮略圖。

  magick script_k.gif -coalesce \
          -bordercolor LightSteelBlue -border 0 \
          -resize 20x20  -layers Optimize   script_k_thumbnail.gif
[IM Output]
==> [IM Output]
這是處理一般 GIF 縮略圖的建議解決方案。任何其他方法都需要人工控制,或者需要非常複雜的 GIF 縮略圖處理邏輯。

色表溢出

最大的問題(就像我在本節開頭提到的那樣)是在圖像中產生了大量的額外顏色,尤其是在線條附近和相鄰顏色區域的邊緣。您還會在圖像邊緣周圍看到半透明顏色的調整大小光暈。這反過來又會增加簡單最小彩色動畫所需的顏色表的大小,這又意味著在保存調整大小的簡單動畫時,文件大小會更大。更糟糕的是,調整大小動畫中的每一幀都可能會生成一組不同的顏色,從而進一步增加“縮略圖”動畫的文件大小。還有一個問題是,在顏色量化之後,您可能不再擁有與原始動畫相同的特定顏色(請參閱量化不會保留顏色)。也就是說,您現在可能沒有純白色的簡單區域,而是灰白色的區域。

使用採樣調整大小

為了避免在調整大小時產生額外的顏色,最簡單的方法是“-sample”動畫,而不是調整動畫大小。這將保留動畫中的當前顏色,並允許您輕鬆地在新的尺寸下重新優化動畫。

  magick script_k.gif -coalesce  -sample 20x20  script_k_sample.gif
[IM Output]
==> [IM Output]
但是,雖然這樣可行,但您基本上是從圖像中刪除像素的行和列,從而在此過程中丟失圖像數據和質量。對於卡通圖像,這通常會留下“點狀”邊框,以及丟失或扭曲的細節。如果您的調整大小超過動畫原始大小的 50%(如上所示),則結果通常非常糟糕,尤其是在動畫中使用了紋理或其他顏色圖案時。因此,許多 GIF 動畫庫中充斥著從網路上複製的這種經過調整大小的糟糕動畫也就不足為奇了。我經常希望他們能清除這種垃圾,但這意味著減少提供的 GIF 數量,這反過來又會降低廣告部門不喜歡的可用 GIF 數量的營銷統計數據。結果,糟糕的 GIF 動畫很常見。

使用液態調整大小調整大小

與使用上述採樣方法類似的方法是使用液態調整大小,也稱為縫隙雕刻。這也會從相關圖像中刪除或添加整個像素,但會嘗試以盡可能保留圖像複雜性的方式進行。查看上面的鏈接,了解如何使用它來生成更精美的調整大小圖像。不幸的是,目前還沒有辦法在一般的動畫圖像上使用它,因為它不了解圖像的複雜性,而且我們目前無法提取調整大小的方法來將其以一致的方式應用於動畫的每一幀。希望這在未來會有所改變。

調整大小並恢復顏色

對動畫進行採樣只會導致刪除像素的行和列,並可能刪除細線和其他重要細節。但是使用“-resize”將像素合併在一起會為 GIF 格式產生過多的新顏色。因此,顯而易見的解決方案是執行“-resize”,然後使用原始動畫顏色通過使用顏色表來恢復調整大小的動畫顏色。
FUTURE: example with original color table restored
這還有一個優點,就是不會生成本地顏色表。但是,在關閉抖動的情況下,結果可能會更好,這樣可以避免任何“抖動噪音”。對於具有大塊平滑顏色區域的卡通圖像來說尤其如此。
FUTURE: non dithered color table restored example

全彩優化

如果您不喜歡可怕的縮圖樣式,那麼您將面臨必須對調整大小後的 GIF 動畫進行完整色彩最佳化的可能性,才能整理出您希望動畫保留的「新」顏色。 然而,對於大多數動畫來說,這通常沒有那麼糟糕,但對於更複雜的動畫(例如將影片轉換為 GIF 動畫時)來說,這可能是一項艱鉅的任務。 也就是說,如果您處理的是卡通動畫,您現在將擁有大量經過反鋸齒處理的線條和邊緣。 對於涉及透明背景的動畫,您還必須正確處理動畫邊緣周圍的半透明像素,這也是由調整大小的反鋸齒功能引起的。 有關處理此問題的許多方法,請參閱GIF 布林透明度一節。

大幅縮減尺寸

當您計劃將大型動畫調整為小得多的動畫時,您將面臨動畫的重要部分消失的問題。 這實際上是靜態圖像和動畫都存在的問題。 有關任何已知的解決方案,請參閱調整線條圖的大小
歡迎提供任何進一步的建議、想法或技巧。

合併多個動畫

我之前說過,但在合併動畫時尤其重要...
盡可能多地了解您正在處理的動畫!
gif2anim」腳本非常適合此目的。 它的姊妹腳本「anim2gif」也常用於此處,以使用其原始設置重新創建動畫。 (請參閱動畫清單資訊中的腳本基本用法。)如果不知道動畫的工作原理,幾乎不可能以各種方式合併它們。 可以開發程式(這些範例的最終目標)來執行此操作。 但是,此類程式通常非常複雜,並且可能會產生意想不到的結果。 因此,您仍然應該遵循這些範例,因為它們將讓您深入了解如何處理和合併動畫。

序列或時間順序附加

使用 IM 將兩個 GIF 動畫連接在一起,使一個序列在時間上接續另一個序列很簡單。 您基本上只需將它們列在命令列中,它們就會彼此跟隨。 但它可能不像看起來那麼容易。 例如,在搜索網路一段時間後,我找到了一些字母繪製動畫(好吧,是為了這個例子而竊取並大量修改的)。 現在我想加入這些圖像,以便當一個動畫完成時,下一個動畫開始,就像有人在寫「OK」這個詞一樣。 以下是字母、「動畫序列」以及這兩個動畫內部的詳細資訊。

  gif2anim -n script_o.gif
  gif2anim -n script_k.gif
 
[IM Text]
[IM Text]
[IM Output]
[IM Output]
這些序列一開始是空白畫布,然後慢慢地向畫布添加和修改像素。它們從不移除、清除或使先前幀添加的任何像素變得透明。然而,出於我們的目的,它們是否這樣做並不重要,因為這對結果幾乎沒有影響。動畫中的幀數也不會對此操作產生影響。重要的是要知道幀的時間安排,因為這可能會產生問題。特別要注意第一幀(在本例中是最後一幀)上的延遲時間。這種技術非常普遍,讓觀看者在動畫清除和重新開始之前有時間看到最終結果。正是這些延遲和幀會在我們按時間追加時造成使用上的問題。另請注意,“k”動畫在動畫序列中間略有延遲。此延遲表示此動畫中第一筆畫的結束和第二筆畫的開始。這種延遲也需要保留,這意味著我們不能僅將動畫中的所有時間序列更改為常數值。上面沒有顯示的是,兩個動畫的第一幀實際上都是空白畫布。我們可能希望在第二個動畫中刪除該畫布,因為這是對時間的無用浪費,儘管它應該保留在第一個動畫中作為開始延遲。現在我們已經檢查了這兩個動畫,讓我們嘗試將它們連接在一起,以便一個動畫在時間上緊隨另一個動畫。

    magick script_o.gif script_k.gif   script_ok_try1.gif
[IM Output]
結果很不理想。字母按正確的順序繪製,但彼此重疊!不僅如此,由於第一個“o”動畫(40 像素)比第二個“k”動畫(53 像素)更細,因此最後一個“k”字母的最後一部分被較小的框架畫布尺寸剪掉了。可以使用相對重新分頁來移動第二個動畫的位置,如上所示。這種重新定位的方法將保留該動畫中可能存在的任何現有偏移,只需將它們全部作為一個相關組移動即可。在這種情況下,幾乎所有幀都具有現有偏移,因為這是一個高度優化的動畫。為了適應這個偏移位置並避免“剪切”第二個動畫,我們还需要擴大整個動畫的畫布尺寸。在讀取第一個動畫或幀之前更改畫布尺寸將擴大動畫運行的畫布區域,並防止“K”被剪切。

    magick -page 90x54 script_o.gif \
            \( script_k.gif -repage +37+0\! \)   script_ok_try2.gif
[IM Output]
結果有了很大的改進。儘管現在繪製字母之間的延遲非常明顯。我們想要的是第一個“O”動畫的最後一幀的延遲要小得多。只要大到看起來像隱形藝術家正在重新定位筆即可。為此,我們複製第一個動畫的最後一幀,然後使用“-set”運算符更改僅該幀的延遲。然後,我們通過刪除原始未修改的圖像將該幀重新添加到圖像序列中。此外,由於我們現在已經在字母繪製之間設置了良好的延遲,因此第二個動畫中的初始空白畫布(僅表示初始開始延遲)現在是多餘的,因此我們可以毫無問題地刪除該幀。如果此幀實際上包含圖像的一部分,那麼我們可能需要調整其延遲,而不是刪除它。

    magick -page 90x54 script_o.gif \( +clone -set delay 20 \) -delete -2 \
            \( script_k.gif -delete 0 -repage +37+0\! \)     script_ok.gif
[IM Output]
我們已經完成了兩個動畫的串聯或時間上的追加,並且修復了與這兩個特定動畫相關的所有小問題。請注意,我從未嘗試過全局更改所有單獨幀或其時間延遲。也就是說,我在實現目標的同時,盡可能保留了原始動畫的內容。這一點很重要,因為並非所有動畫都在幀之間使用恆定的時間延遲,更改此延遲可能會使動畫看起來非常糟糕。

並排附加(時間同步)

假設您希望將兩個動畫並排追加,但希望動畫的兩個部分同時進行動畫處理。這並不容易,因為您需要將兩個動畫中的每一對幀追加(或組合在一起),以便動畫也能協同工作。這樣做的真正問題是 IM 命令列只能處理單個圖像序列。它沒有 API 的奢侈功能,您可以在其中保留兩個獨立的圖像序列,循環瀏覽它們並將它們追加到第三個序列中。我可以想到三種基本技術來完成這種追加。在開始之前,您應該首先研究這兩個動畫,檢查時間序列和動畫的其他細節。“gif2anim”腳本很適合執行此操作,生成的“.anim”文件稍後會很有用。

  gif2anim -n bag_left.gif
  gif2anim -n bag_right.gif
 
[IM Text]
 
[IM Text]
[left]
[right]
如果您查看信息摘要,您會發現兩個動畫具有完全相同的幀數,並且時間序列幾乎完全相同。這裡重要的是時間的一致性,您可以說動畫已經“時間同步”。然而,雖然時間安排可能正確,但動畫是幀優化的,而不是完全合併的。但是畫布區域高度相同,因此可以實際並排追加兩幀。實際上,這個動畫被嚴重地“分割”(請參閱下一個示例集中的分割動畫),因此“貓”動畫被一分為二,原始動畫丟失了。其他修改導致時間上有非常輕微的差異,這只會使劃分更加明顯。這是gmabrysIM 論壇的討論中向我提出的問題,儘管他給出的實際問題要糟糕得多。[left][right]現在,瀏覽器通常會分別為每個 GIF 圖像製作動畫,而無需任何同步。因此,這兩個動畫可能會彼此不同步,從而產生一隻看起來像是電鋸大屠殺一部分的“貓”。您可能會在右側看到這種效果,我在瀏覽器頁面上並排放置了兩個動畫,尤其是在您通過慢速鏈路連接到遠程服務器時。現在讓我們嘗試將它們正確同步到一個動畫圖像中。

追加單獨的文件

最簡單的方法是合併兩個動畫並將它們分離成單獨的圖像文件,每幀一個圖像。然後可以根據需要將單獨的圖像追加在一起(或以其他方式修改幀)。完成後,可以使用新幀重建動畫。但是,這需要您保存大量有關動畫的額外信息,這些信息在處理過程中很容易丟失。

  # Separate animations into coalesced frames (plus a ".anim" file)
  gif2anim -c bag_left.gif
  gif2anim -c bag_right.gif

  # Append the separated frames them together
  for i in `seq -f '%03g' 1 11`; do \
    magick bag_left_$i.gif bag_right_$i.gif +append bag_append_$i.gif; \
  done

  # Rebuild the animation (using one of the ".anim" files)
  anim2gif -c -b bag_append  bag_left.anim

  # Cleanup
  rm -f bag_left.anim bag_right.anim
  rm -f bag_{left,right,append}_???.gif
[IM Output]
如您所見,這是一個相當複雜的過程,會產生許多單獨的臨時圖像,因此在完成後需要進行大量清理。當然,如果您正在調試上述內容,則單獨的臨時文件可以更輕鬆地找出處理過程中出現的問題。它也顯示了“gif2anim”腳本的強大功能,並且與“anim2gif”腳本相反,它可以分離和保存動畫元數據,然後再重新構建 GIF 動畫。基本上,它允許您保留動畫的原始時間,而無需直接在腳本中對其進行編碼。最終圖像仍然需要重新優化,但在這種情況下,由於在每幀之間的整個動畫過程中同時發生了很多事情,因此您將獲得很少的優化

分層合成

一種更好的技術是使用多圖像列表 圖層合成 來疊加動畫。這僅涉及放大一組圖像,然後疊加另一組圖像以將它們連接在一起。事實上,這就是普通的“-append”運算符在內部所做的,因此並沒有太大不同。在這裡,我只是告訴 IM 畫布的大小,然後使用“-coalesce”填充它。然後,我將其他合併的動畫與適當的偏移量疊加。

  magick bag_left.gif -repage 97x92 -coalesce \
          null: \( bag_right.gif -coalesce \) \
          -geometry +50+0 -layers Composite    bag_append.gif
[IM Output]
當然,上述技術意味著我需要知道最終動畫的大小,以及疊加動畫所需的偏移量。但該過程速度很快,效果很好,並且腳本命令可以預先讀取圖像以確定該信息。為了製作更通用的動畫附加方法,我們需要做一些花哨的圖像處理來自動確定附加的最終大小和偏移量。要在不預讀動畫的情況下做到這一點,需要跳過一些環節,但可以通過單個命令進行一般的動畫附加。首先,我們需要附加每個動畫的第一個合併幀以創建大小合適的畫布,然後清除它。第一個動畫被合併並覆蓋到畫布的左半部分,然後第二個動畫被合併並使用“-gravity East”覆蓋以將其放置在預先準備好的畫布的最右側,以避免需要偏移量。

  magick bag_left.gif'[0]' -coalesce \( bag_right.gif'[0]' -coalesce \) \
          +append -channel A -evaluate set 0 +channel \
          bag_left.gif -coalesce -delete 0 \
          null: \( bag_right.gif -coalesce \) \
          -gravity East  -layers Composite    bag.gif
[IM Output]
現在,您就有了一種將兩個時間同步的動畫附加在一起的通用技術。

雙重附加、附加 - 或附加動畫字體

在完成附加動畫之前,我想向您展示另一種技術。這種技術可以同時附加多個動畫,但代價是丟失所有存在的时间信息。通常(但不總是)這些時間並不是什麼大不了的損失。基本上,我們將每個動畫的所有幀垂直附加到一個圖像中,然後將整個動畫作為兩個簡單圖像附加或覆蓋。這有點像將兩條電影膠片並排粘在一起以產生更寬的電影膠片。

  magick \( bag_left.gif  -coalesce -append \) \
          \( bag_right.gif -coalesce -append \) \
          +append  -crop x92 +repage \
          -set delay 30     bag_dbl_append.gif
[IM Output]
這不需要任何臨時檔案,但正如我在開始時提到的,所有原始的時間延遲都已遺失。在此範例中,我只是將所有動畫延遲設定為一個常數值,產生了一個合理但不同的結果。此外,為了重新構建動畫,我們需要知道原始動畫的幀高度,以便正確地分割(平鋪裁剪)加寬的“膠片”。雖然可以使用“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] [IM Output] [IM Output] [IM Output] [IM Output] ==> [IM Output]
您還可以做一些更花哨的事情,例如調整結果動畫中的時間和循環次數。

  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]
前兩行構成了標誌中“始終亮起”的部分(之前每個動畫字母的第一幀)。在此之後,添加最後一個“壞掉的”字母,並將整個動畫加倍幾次以產生大約 16 幀。設定時間以完成所需的效果,第一幀和最後一幀顯示較長時間,而其餘幀則快速閃過(“-delay 10”)。實際上,這個 GIF 動畫比您想像的幀數要小得多。基本上,IM GIF 優化器發現它只需要每隔一幀重新覆蓋“O”動畫,並使用“上一幀”處置來恢復之前點亮的“O”。因此,該動畫僅比基本的閃爍未優化的“hello”圖像大 50%。自己檢查一下。*你能改進霓虹燈動畫嗎?讓它更逼真?遺憾的是,GIF 動畫沒有聲音。*

分割動畫

現在我們已經將動畫重新連接在一起,讓我們嘗試將其正確分割以供在網路伺服器上使用,以便各個部分可以單獨動畫化,而不會互相干擾。這實際上相當困難,我不會嘗試完全自動化這個過程。但是,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] ==> [IM Output]
現在我們可以看到這個動畫可以分為至少三個區域:頂部的“貓”區域、左側的小“熊”和右側的拍打“翅膀”。所有這些都使用簡單的正交(垂直或水平)切割。
所以讓我們就這樣做,使用一些簡單的動畫的視口裁剪

  magick bag.gif -coalesce  -crop 97x39+0+0\!   bag_cat.gif
  magick bag.gif -coalesce  -crop 50x54+0+39\!  bag_bear.gif
  magick bag.gif -coalesce  -crop 47x54+50+39\! bag_wing.gif
[IM Output]
[IM Output] [IM Output]
這三個圖像可以由瀏覽器一起顯示,並且不會有「德州電鋸殺人狂」的外觀,因為在任何時候,子動畫都不會跨越另一個動畫的邊界。從技術上講,你可以進行更多切割,以便將未動畫化的區域與動畫化區域分開,將此動畫拆分為大約六個或更多區域,儘管這樣做不會從優化中獲得太多收益。它實際上只會使你的網頁複雜化,並為用戶創建更多文件以下載。現在,與較大的動畫不同,這些較小的區域將彼此完全獨立地進行動畫處理。我們甚至可以更改這些簡單子動畫的時間安排,而不會對結果產生負面影響,從而使它們與其他子動畫完全不同步。結果是一個更好、重複性更低的動畫圖像(見下文)。如果你研究「彈跳熊」和「拍打翅膀」,你會發現它們形成了一個簡單的兩幀循環,只是簡單地重複多次,以匹配揮手貓的時間安排。因此,我們可以刪除額外的重複以簡化這些動畫。「貓」的前兩幀也完全相同。然而,與「熊」和「翅膀」不同,你不能只刪除其中一個,因為每一幀都包含時間延遲,以允許「熊」和「翅膀」在沒有貓的情況下進行動畫處理。要正確刪除這些重複的幀,你需要使用「-layer」方法「RemoveDups」來定位和合併合併動畫中此類重複幀的時間安排。以下是所有三個分離動畫的最終優化,以及時間安排更改,以改進子動畫的整體去同步化。我還在頁面上並排顯示了所有三個動畫,就像它們應該顯示的那樣。

  magick bag_cat.gif -layers RemoveDups \
                           -quiet  -layers Optimize  bag_cat_opt.gif
  magick bag_bear.gif -delete 2--1 -set delay 47 \
                                   -layers Optimize  bag_bear_opt.gif
  magick bag_wing.gif -delete 2--1 -set delay 33 \
                                   -layers Optimize  bag_wing_opt.gif
 
[IM Output]
[IM Output] [IM Output]
 
最後總結一下:兩個原始(分割不良)圖像總共 [IM 文字] 位元組,這與附加版本大致相同。在正確分割動畫後,可以很好地優化子動畫,我們在三個圖像上總共獲得了 [IM 文字] 位元組。相當不錯的節省。

遠距離變更幀分割

施工中
分割「兩個相距很遠的變化對象」的幀更新示例,不涉及透明度(固定背景),但保留了各部分之間的時間同步。然後使用透明背景重複,(需要「OptimizePlus」來生成「清除」的像素。有關一般示例,請參見 分割幀動作

合併時間不相交的動畫

在將任何兩個動畫合併在一起同步運行之前,你需要使所有動畫使用相同的幀數,並使用相同的時間延遲集。合併的難度實際上取決於動畫時間安排的不相交程度。如果時間延遲基本上是恆定的,你可以簡單地忽略它們並在以後修復時間安排。在 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)