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