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

在下面的鏈接中,您可以找到本文中將要參考的所有代碼的實(shí)時(shí)預(yù)覽:
- ? 預(yù)覽:
- 索引:gsap-animation-to-gif.netlify.app
- 簡易版:gsap-animation-to-gif.netlify.app/simple
- ?? 代碼庫:github.com/PaulieScanlon/gsap-animation-to-gif
代碼庫中有兩個(gè)“頁面”。 index 包含上面 GIF 的所有代碼,simple 是本文中介紹的步驟的起點(diǎn)。
如何將 GSAP 動(dòng)畫轉(zhuǎn)換為 GIF
我用來將 GSAP 動(dòng)畫轉(zhuǎn)換為 GIF 的方法涉及在補(bǔ)間的每次“更新”時(shí)捕獲 SVG 數(shù)據(jù)並將其寫入 HTML 畫布。補(bǔ)間完成後,我就可以將 SVG 數(shù)據(jù)轉(zhuǎn)換為光柵化圖像數(shù)據(jù),modern-gif 可以使用它來創(chuàng)建動(dòng)畫 GIF 的每一幀。
入門
這是我在簡單示例中使用的代碼,我將用它來解釋從 GSAP 動(dòng)畫創(chuàng)建動(dòng)畫 GIF 所需的每個(gè)步驟:
<!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' });
此步驟稍微複雜一些,需要對(duì) animationFrames 數(shù)組的每個(gè)索引執(zhí)行一個(gè)操作。
通過使用遞歸函數(shù) renderSvgDataToCanvas,我可以使用 animationFrames 數(shù)組中的圖像數(shù)據(jù),將其寫入畫布。然後,通過使用 canvas.toDataURL('image/jpeg'),我可以將動(dòng)畫每一幀的光柵化數(shù)據(jù)存儲(chǔ)在 canvasFrames 數(shù)組中。
如果已在 onComplete 函數(shù)中添加 console.log,則應(yīng)在瀏覽器控制臺(tái)中看到類似於以下內(nèi)容。但是,這次請(qǐng)注意數(shù)據(jù)的 MIME 類型:它不是 svg xml,而是 image/jpeg。這對(duì)於我接下來要做的工作很重要。

將光柵化數(shù)據(jù)轉(zhuǎn)換為 GIF
這是最後一步,它涉及將 canvasFrames 數(shù)組的每個(gè)索引傳遞到 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)換為“另一個(gè)”MIME 類型,這次是 image/gif。
一旦我有了表示動(dòng)畫 GIF 的最終“blob”數(shù)據(jù),我就將其轉(zhuǎn)換為 URL,然後設(shè)置 image 和 link 元素的 src 和 href,以便我可以在瀏覽器中查看和下載 GIF。

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