摘要:文章首發(fā)于個(gè)人博客在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。
文章首發(fā)于個(gè)人博客:http://heavenru.com
在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。在這篇文章中,主要是介紹兩個(gè)命令行工具來實(shí)現(xiàn)將一個(gè)短視頻文件轉(zhuǎn)化成一張 sprite 圖片與如何使用 canvas 繪制精靈動(dòng)畫
兩個(gè)工具官方地址如下:
ffmpeg
montage
1、ffmpeg 視頻轉(zhuǎn)圖片工具ffmpeg 是「一個(gè)完整的跨平臺(tái)解決方案,用于記錄,轉(zhuǎn)換和流式傳輸音頻和視頻的工具」,它的作用原不止于這篇文章中所介紹的,有興趣的同學(xué)可以自己去官方網(wǎng)站了解更多。
將視頻轉(zhuǎn)成圖片輸出 基本用法./ffmpeg -i jellyfish.mp4 -vf scale=138:-1 -r 8 %04d.png
-i 視頻流輸入 URL
-vf 創(chuàng)建由過濾器指定的過濾器,并使用它過濾流,過濾器是要應(yīng)用于流的過濾器的描述,并且必須具有相同類型流的單個(gè)輸入和單個(gè)輸出。對(duì)應(yīng)的過濾器參數(shù)必須跟在這個(gè)之后,不然無法生效
scale 視頻縮放,scale=width:height 其中,如果 height=-1 ,則表示自適應(yīng)高度,按照視頻的寬高比輸出,后面緊接這 scale=width:height,setar=16:9 則可以指定輸出寬高比
-r 視頻輸出 fps 值, 值越大,則以越高的 fps 切片視頻,別名 -framerate,比如我們想以 60fps 去裁剪視頻導(dǎo)出圖片,則使用 -r 60
-aspect 視頻輸出寬高比,比如常用的 4:3、16:9 都是規(guī)范的參數(shù)用法
-ss 裁剪開始位置,表示從視頻的某個(gè)時(shí)間開始裁剪,是一個(gè)非常有用的參數(shù),該參數(shù)使用位置放在 -i 前面,參數(shù)格式 hh:mm:ss 表示時(shí)分秒
-t 持續(xù)時(shí)間,表示需要裁剪的視頻長度,通常配合 -ss 一起使用,就能實(shí)現(xiàn)裁剪任意視頻時(shí)間段的內(nèi)容了,比如我們需要裁剪 5-10 秒的視頻導(dǎo)出,可以這么配合使用 ffmgeg -ss 00:00:05 -t 00:00:10
-vframes 設(shè)定輸出視頻幀數(shù),它是 -frames:v 的別名
-qscale:v 2 指定輸出圖片質(zhì)量,取值范圍2-31,值越大,質(zhì)量越差,建議取值 2-5
綜合應(yīng)用:// 截取 60 秒處的一張圖片 ffmpeg -ss 60 -i input.mp4 -qscale:v 2 -vframes 1 output.jpg // 將視頻按照 60fps 的速度導(dǎo)出所有圖片 ffmpeg -i input.mp4 -r 60 %04d.png2、合并多個(gè)圖片為一張圖片 montage
通過上面介紹的工具,我們能很輕易的將一個(gè)視頻轉(zhuǎn)化為一系列的圖片文件,那么這個(gè)時(shí)候,我們就可以使用 montage 工具將前面導(dǎo)出的 n 張圖片合并為一張圖片
基本用法:montage -border 0 -geometry 138x -tile 89x -quality 100% *.png myvideo.jpg
-tile 代表需要合并的一行圖片數(shù)量,當(dāng)超出這個(gè)數(shù)字的時(shí)候,將換行合并
-quality 代表合成圖片質(zhì)量,取值范圍 0 - 100%
3、繪制 canvas 精靈動(dòng)畫在開始編輯代碼之前,我們整理一下需求:
動(dòng)畫需要能循環(huán)播放
動(dòng)畫需要能指定從某一幀開始渲染
指定渲染多少幀動(dòng)畫
動(dòng)畫需要能控制渲染幀率
當(dāng)精靈圖片不是單行的時(shí)候,要能實(shí)現(xiàn)自動(dòng)換行渲染
OK,明白了我們的需求之后,我們開始編寫代碼。先來一個(gè)簡易的參數(shù)合并工具方法
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) { // 遍歷傳入的對(duì)象的屬性
if (Object.prototype.hasOwnProperty.call(source, key)) { // 只操作該實(shí)例上的屬性和方法, 避免循環(huán)原型
target[key] = source[key];
}
}
}
return target;
}
接下來是我們的 canvas 精靈對(duì)象
function Sprite(canvas, opts) {
var defaults = {
loop: false, // 是否循環(huán)播放
frameIndex: 0, // 當(dāng)前第幾幀
startFrameIndex: 0, // 其實(shí)渲染位置
tickCount: 0, // 每個(gè)時(shí)間段內(nèi)計(jì)數(shù)器
ticksPerFrame: 1, // 每個(gè)渲染時(shí)間段幀數(shù),通過這個(gè)來控制動(dòng)畫的渲染速度
numberOfFrames: 1, // 動(dòng)畫總幀數(shù)
numberOfPerLine: undefined, // 每行動(dòng)畫幀數(shù)
width: 0, // 畫布寬度
height: 0, // 畫屏高度
sprite: undefined // 圖片 image 對(duì)象
};
var params = opts || {};
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.options = _extends({}, defaults, params);
if (this.image) throw new Error("請(qǐng)傳入圖片對(duì)象");
// 這里的取 Math.min() 的原因是,在 safari 下面,如果圖片的大小超過了畫布的大小,那么將不會(huì)渲染任何圖像
// 所以在這里,我們?nèi)ギ嫴己蛨D片中的小者。
this.options.width = Math.min(this.canvas.width, this.options.sprite.width);
this.options.height = Math.min(this.canvas.height, this.options.sprite.height);
if (!this.options.numberOfPerLine) {
this.options.numberOfPerLine = this.options.numberOfFrames || 9999;
}
}
Sprite.prototype.render = function () {
this.ctx.clearRect(0, 0, this.options.width, this.options.height);
// 核心繪制代碼,主要使用了 canvas.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) API
// this.options.frameIndex % this.options.numberOfPerLine 每次求余數(shù),判斷是否換行
// Math.floor(this.options.frameIndex / this.options.numberOfPerLine)
this.ctx.drawImage(this.options.sprite, this.options.width * (this.options.frameIndex % this.options.numberOfPerLine), this.options.height * Math.floor(this.options.frameIndex / this.options.numberOfPerLine), this.options.width, this.options.height, 0, 0, this.options.width, this.options.height);
}
Sprite.prototype.update = function () {
this.options.tickCount++;
// 控制幀率的核心部分,在每個(gè)繪制時(shí)間點(diǎn),判斷當(dāng)前的計(jì)數(shù)器是否大于我們傳入的值
if (this.options.tickCount > this.options.ticksPerFrame) {
this.options.tickCount = 0;
// 動(dòng)畫循環(huán)判斷
if (this.options.frameIndex < this.options.numberOfFrames - 1) {
this.options.frameIndex++;
} else if (this.options.loop) {
// 每次循環(huán)都從給定的 startFrameIndex 開始
this.options.frameIndex = this.options.startFrameIndex;
}
}
}
到這里,我們的精靈類基本完成了,接下來看下具體在業(yè)務(wù)代碼中如何使用它
var spriteCanvas = document.getElementById("spriteCanvas");
spriteCanvas.width = 138;
spriteCanvas.height = 308;
var isSpriteLoaded = false;
var spriteImage = new Image();
var sprite;
// 這里有個(gè) IE 下的 BUG,如果我們的 sprite 在圖片沒有加載完全就執(zhí)行
// 那么在 IE 下面會(huì)拋出一個(gè) DOM Exception
// 因此我們將 Sprite 初始化放在了 image.onlaod 回調(diào)函數(shù)中執(zhí)行
sprite.onload = function () {
sprite = new Sprite(spriteCanvas, {
sprite: spriteImage,
loop: true,
numberOfFrames: 92,
ticksPerFrame: 3
});
spriteAnimate();
}
sprite.src = "xxxxx/sprite.jpg";
function spriteAnimate() {
requestAnimationFrame(spriteAnimate);
sprite.render();
sprite.update();
}
文章到這里基本完成了,想要看具體效果的同學(xué),可以去這里查看
傳送門: 水母動(dòng)畫, 蜂鳥動(dòng)畫
https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage
http://www.williammalone.com/articles/create-html5-canvas-javascript-sprite-animation/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/112336.html
摘要:文章首發(fā)于個(gè)人博客在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。 文章首發(fā)于個(gè)人博客:http://heavenru.com 在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。在這篇文章中,主要是介紹兩個(gè)命令行工具來實(shí)現(xiàn)將一個(gè)短視頻...
摘要:文章首發(fā)于個(gè)人博客在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。 文章首發(fā)于個(gè)人博客:http://heavenru.com 在最近項(xiàng)目中需要實(shí)現(xiàn)一個(gè)精靈動(dòng)畫,素材方只提供了一個(gè)短視頻素材,所以在實(shí)現(xiàn)精靈動(dòng)畫之前先介紹兩個(gè)工具來幫助我們更好的實(shí)現(xiàn)需求。在這篇文章中,主要是介紹兩個(gè)命令行工具來實(shí)現(xiàn)將一個(gè)短視頻...
摘要:項(xiàng)目中文字由進(jìn)行渲染。待觸發(fā)時(shí),取消中文輸入標(biāo)記,將文字渲染到上。而其中一些有趣的細(xì)節(jié)實(shí)現(xiàn)如文本渲染,對(duì)中文筆畫分割實(shí)現(xiàn)有趣的動(dòng)畫等并沒有描寫。 導(dǎo)言 目前富文本編輯器的實(shí)現(xiàn)主要有兩種技術(shù)方案:一個(gè)是利用contenteditable屬性直接對(duì)html元素進(jìn)行編輯,如draft.js;另一種是代理textarea + 自定義div + 模擬光標(biāo)實(shí)現(xiàn)。對(duì)于類似word的經(jīng)典富文本編輯器,...
閱讀 910·2021-09-29 09:34
閱讀 2718·2019-08-30 15:53
閱讀 3536·2019-08-29 17:17
閱讀 972·2019-08-29 16:08
閱讀 1344·2019-08-29 13:03
閱讀 1100·2019-08-27 10:54
閱讀 885·2019-08-26 13:39
閱讀 3018·2019-08-26 13:34