將 GSAP 動畫轉(zhuǎn)換為動畫 GIF:使用 modern-gif 的分步指南
關(guān)鍵要點
- 可以使用一個過程將 GSAP 動畫轉(zhuǎn)換為動畫 GIF,該過程涉及在每次調(diào)整補間時捕獲 SVG 數(shù)據(jù)并將其寫入 HTML 畫布。然后,可以將此 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化圖像數(shù)據(jù),然后由 modern-gif 用于創(chuàng)建動畫 GIF 的每一幀。
- 轉(zhuǎn)換過程涉及多個步驟,包括捕獲 SVG 數(shù)據(jù)、將 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化數(shù)據(jù),最后將光柵化數(shù)據(jù)轉(zhuǎn)換為 GIF。每個步驟都涉及特定的代碼修改和使用數(shù)組來存儲捕獲和轉(zhuǎn)換的數(shù)據(jù)。
- 由于瀏覽器動畫和 GIF 之間的幀速率通常不同,因此最終 GIF 的幀速率可能比原始動畫慢。為了加快 GIF 的速度,可以使用數(shù)組過濾器和 JavaScript 余數(shù)運算符來確定索引是否可以被某個數(shù)字整除,從而丟棄一些幀。
本文將解釋如何使用 modern-gif 將使用 GSAP 創(chuàng)建的動畫轉(zhuǎn)換為動畫 GIF。
以下是一個我之前制作的動畫預(yù)覽:

在下面的鏈接中,您可以找到本文中將要參考的所有代碼的實時預(yù)覽:
- ? 預(yù)覽:
- 索引:gsap-animation-to-gif.netlify.app
- 簡易版:gsap-animation-to-gif.netlify.app/simple
- ?? 代碼庫:github.com/PaulieScanlon/gsap-animation-to-gif
代碼庫中有兩個“頁面”。index 包含上面 GIF 的所有代碼,simple 是本文中介紹的步驟的起點。
如何將 GSAP 動畫轉(zhuǎn)換為 GIF
我用來將 GSAP 動畫轉(zhuǎn)換為 GIF 的方法涉及在補間的每次“更新”時捕獲 SVG 數(shù)據(jù)并將其寫入 HTML 畫布。補間完成后,我就可以將 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化圖像數(shù)據(jù),modern-gif 可以使用它來創(chuàng)建動畫 GIF 的每一幀。
入門
這是我在簡單示例中使用的代碼,我將用它來解釋從 GSAP 動畫創(chuàng)建動畫 GIF 所需的每個步驟:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Simple</title>
</head>
<body>
<main>
<svg id='svg'
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 400 200'
width={400}
height={200}
style={{ border: '1px solid red' }}
>
<rect id='rect' x='0' y='75' width='50' height='50' fill='red'></rect>
</svg>
<canvas id='canvas' style={{ border: '1px solid blue' }} width={400} height={200}></canvas>
<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173898187373194.jpg" class="lazy" alt="How to Create Animated GIFs from GSAP Animations " /></p>
<h2>將 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化數(shù)據(jù)</h2>
<pre class="brush:php;toolbar:false"><code class="javascript">gsap.timeline({
onUpdate: () => {
const xml = new XMLSerializer().serializeToString(svg);
const src = `data:image/svg+xml;base64,${btoa(xml)}`;
animationFrames.push(src);
},
onComplete: () => {
let inc = 0;
const renderSvgDataToCanvas = () => {
const virtualImage = new Image();
virtualImage.src = animationFrames[inc];
virtualImage.onload = () => {
ctx.clearRect(0, 0, 400, 200);
ctx.drawImage(virtualImage, 0, 0, 400, 200);
canvasFrames.push(canvas.toDataURL('image/jpeg'));
inc++;
if (inc < animationFrames.length) {
renderSvgDataToCanvas();
} else {
//console.log(canvasFrames); //調(diào)試用
generateGif();
}
};
};
renderSvgDataToCanvas();
},
})
.fromTo('#rect', { x: -50 }, { duration: 2, x: 350, ease: 'power.ease2' });
此步驟稍微復(fù)雜一些,需要對 animationFrames 數(shù)組的每個索引執(zhí)行一個操作。
通過使用遞歸函數(shù) renderSvgDataToCanvas,我可以使用 animationFrames 數(shù)組中的圖像數(shù)據(jù),將其寫入畫布。然后,通過使用 canvas.toDataURL('image/jpeg'),我可以將動畫每一幀的光柵化數(shù)據(jù)存儲在 canvasFrames 數(shù)組中。
如果已在 onComplete 函數(shù)中添加 console.log,則應(yīng)在瀏覽器控制臺中看到類似于以下內(nèi)容。但是,這次請注意數(shù)據(jù)的 MIME 類型:它不是 svg xml,而是 image/jpeg。這對于我接下來要做的工作很重要。

將光柵化數(shù)據(jù)轉(zhuǎn)換為 GIF
這是最后一步,它涉及將 canvasFrames 數(shù)組的每個索引傳遞到 modern-gif。
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Simple</title>
</head>
<body>
<main>
<svg id='svg'
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 400 200'
width={400}
height={200}
style={{ border: '1px solid red' }}
>
<rect id='rect' x='0' y='75' width='50' height='50' fill='red'></rect>
</svg>
<canvas id='canvas' style={{ border: '1px solid blue' }} width={400} height={200}></canvas>
<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173898187373194.jpg" class="lazy" alt="How to Create Animated GIFs from GSAP Animations " /></p>
<h2>將 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化數(shù)據(jù)</h2>
<pre class="brush:php;toolbar:false"><code class="javascript">gsap.timeline({
onUpdate: () => {
const xml = new XMLSerializer().serializeToString(svg);
const src = `data:image/svg+xml;base64,${btoa(xml)}`;
animationFrames.push(src);
},
onComplete: () => {
let inc = 0;
const renderSvgDataToCanvas = () => {
const virtualImage = new Image();
virtualImage.src = animationFrames[inc];
virtualImage.onload = () => {
ctx.clearRect(0, 0, 400, 200);
ctx.drawImage(virtualImage, 0, 0, 400, 200);
canvasFrames.push(canvas.toDataURL('image/jpeg'));
inc++;
if (inc < animationFrames.length) {
renderSvgDataToCanvas();
} else {
//console.log(canvasFrames); //調(diào)試用
generateGif();
}
};
};
renderSvgDataToCanvas();
},
})
.fromTo('#rect', { x: -50 }, { duration: 2, x: 350, ease: 'power.ease2' });
使用 modernGif.encode,您可以將數(shù)據(jù)數(shù)組傳遞到 frames 并為每一幀定義延遲,我選擇添加 0 秒的延遲。
代碼的下一部分處理轉(zhuǎn)換 modernGif.ecode 數(shù)據(jù)并將其轉(zhuǎn)換為“另一個”MIME 類型,這次是 image/gif。
一旦我有了表示動畫 GIF 的最終“blob”數(shù)據(jù),我就將其轉(zhuǎn)換為 URL,然后設(shè)置 image 和 link 元素的 src 和 href,以便我可以在瀏覽器中查看和下載 GIF。

幀速率
您可能會注意到最終的 GIF 運行速度相當(dāng)慢,這是因為在瀏覽器中運行的動畫通常每秒播放 60 幀 (fps),而 GIF 的幀速率通常要慢得多,為 12 或 24 fps。
為了“丟棄”一些動畫幀,我使用數(shù)組過濾器和 JavaScript 余數(shù)運算符來確定索引是否可以被某個數(shù)字整除,在我的例子中,我選擇 6。不能被 6 整除的索引將從數(shù)組中過濾掉。生成的動畫 GIF 雖然有點笨拙,但播放速度會快得多。
我已經(jīng)在 generateGif
函數(shù)中添加了 filter
方法來實現(xiàn)幀速率的調(diào)整。
就是這樣,您可以通過 HTML 畫布將 GSAP SVG 動畫轉(zhuǎn)換為動畫 GIF!
如果您對本文中描述的任何內(nèi)容有任何疑問,請隨時在 Twitter/X 上找到我:@PaulieScanlon。
以上是如何從GSAP動畫創(chuàng)建動畫GIF的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!