需求說明
前端實現(xiàn)視頻截取片段,并轉(zhuǎn)換為gif圖片下載到本地
參考文檔
HTML5 CSS3 誘人的實例 :模仿優(yōu)酷視頻截圖功能
github antimatter15
結(jié)果說明
純前端通過canvas截幀并可以保存為gif形式當(dāng)前在移動端chrome、safari瀏覽器支持較好牲尺。
demo展示
canvas截圖圖片實例
- 截取圖片
在截取視頻之前疆柔,首先進(jìn)行了截取圖片的嘗試。截取圖片或者視頻主要使用了canvas的CanvasRenderingContext2D.drawImage()
MDN說明該函數(shù)可以在canvas畫布上繪制圖像,繪制圖像后通過HTMLCanvasElement.toDataURL()
函數(shù)返回一個包含圖片展示的dataUrlMDN說明
this.canvas = document.createElement("canvas”);
this.ctx = this.canvas.getContext("2d”);
this.ctx.drawImage( this.img,0,0,this.Width, this.Height,0,0,this.Width,this.Height);
let dataUrl = this.canvas.toDataURL("image/png”);
- 轉(zhuǎn)成gif下載
轉(zhuǎn)成gif下載主要使用了jsgif
中的如下代碼菇肃,引入了 如下JS文件
<script type="text/javascript" src="LZWEncoder.js"></script>
<script type="text/javascript" src="NeuQuant.js"></script>
<script type="text/javascript" src="GIFEncoder.js"></script>
<script type="text/javascript" src="b64.js"></script>
這里需要注意的是
encoder.addFrame(context);
中傳遞的context參數(shù)拂玻,文檔中說或者是canvas元素酸些,或者是imageData形式。那么imageData.data類型要怎么獲取到呢檐蚜?通過函數(shù)CanvasRenderingContext2D.getImageData()
MDN說明,該函數(shù)可以返回一個imageDataMDN說明對象魄懂,ImageData.data是[Uint8ClampedArray
]類型,描述了一個一維數(shù)組闯第,包含以 RGBA 順序的數(shù)據(jù)市栗,數(shù)據(jù)使用(包含)的整數(shù)表示。將ImageData.data傳入encoder.addFrame即可,這樣就實現(xiàn)了canvas截圖后并將其轉(zhuǎn)成gif形式填帽。
let context = this.ctx.getImageData(0,0,this.Width,this.Height).data
var encoder = new GIFEncoder();
encoder.setRepeat(0); //0 -> loop forever
//1+ -> loop n times then stop
encoder.setDelay(10); //這里單張圖片并不需要用到蛛淋,用于設(shè)置幀數(shù)間隔時間
encoder.start();
encoder.setSize(640, 430); //此處應(yīng)和canvas獲得的圖片尺寸一致
encoder.addFrame(context, true);
encoder.finish();
encoder.download("download.gif");
- gif下載
單張圖片是完全沒有必要下載成gif的,這個主要是為了視頻截取而準(zhǔn)備篡腌,在GIFEncoder.js中褐荷,主要采用如下代碼實現(xiàn)了圖片下載。
ar templink = document.createElement("a");
templink.download=filename;//filename = ‘download.gif'
templink.href= URL.createObjectURL(new Blob([new Uint8Array(out.bin)], {type : "image/gif" } ))
console.log(templink)
templink.click()
在上面代碼中templink得到的是如下一個超鏈接標(biāo)簽嘹悼,在chrome中執(zhí)行click()會直接下載該文件叛甫,safari則會打開一個新的頁面
<a download="download.gif" href="blob:http://xxxxxx:3023/12465504-7074-466a-8828-29ee44848612"></a>
上面創(chuàng)建下載鏈接主要是采用了URL.createObjectURL()
對象MDN說明
MDN上說該靜態(tài)方法會創(chuàng)建一個 [DOMString
]其中包含一個表示參數(shù)中給出的對象的URL。這個 URL 的生命周期和創(chuàng)建它的窗口中的 [document
]綁定杨伙。這個新的URL 對象表示指定[File
]對象或 [Blob
]對象
Blob對象表示不可變的類似文件對象的原始數(shù)據(jù)其监。Blob表示不一定是JavaScript原生形式的數(shù)據(jù)。 File 接口基于Blob限匣,繼承了 blob的功能并將其擴(kuò)展使其支持用戶系統(tǒng)上的文件對象
這里對Blob的理解并不深刻抖苦,上面獲取的href地址從測試結(jié)果來看,uc米死、QQ等瀏覽器是不支持其打開預(yù)覽下載的锌历。所以這個合成gif并下載的功能在chrome和safari可支持使用。
canvas截取視頻實例
截取視頻和截取圖片的區(qū)別在于視頻是多次截取拼成gif圖片哲身,在截圖辩涝、轉(zhuǎn)成GIF、下載與截取圖片所用核心代碼基本一致勘天,差別只在于視頻需要設(shè)置起始于結(jié)束時間怔揩,該時間段內(nèi)setInterval循環(huán)繪制canvas圖片,循環(huán)繪制后脯丝,生成imageData.data的數(shù)組商膊,該數(shù)組循環(huán)調(diào)用encoder.addFrame(context, true)
方法。
事件主要代碼如下:
var draw = new drawVideo($('video')[0]);
document.getElementById('j_begin').addEventListener('click',()=>{
document.getElementById('video').currentTime = startTime;
document.getElementById('video').play();
var time = setInterval(()=>{
draw.paint();
document.getElementById('video').play(); //每次繪制完需要將視頻播放
if(document.getElementById('video').currentTime > endTime){//超過當(dāng)前結(jié)束時間停止繪制canvas
console.log('stop');
clearInterval(time);
var encoder = new GIFEncoder();
encoder.setRepeat(0); //0 -> loop forever
//1+ -> loop n times then stop
encoder.setDelay(300); //這個時間的設(shè)置會影響gif展現(xiàn)時的速度
encoder.start();
encoder.setSize(1280, 720);//此處高度應(yīng)為視頻寬高
draw.result.forEach((ele,index)=>{
encoder.addFrame(ele, true);//循環(huán)添加canvas的每一幀合成gif
})
encoder.finish();
encoder.download("download.gif");
}
},1500);//1500秒為循環(huán)時間宠进,如果時間設(shè)置太短看晕拆,手機(jī)上卡頓特別明顯,時間設(shè)置太長材蹬,生產(chǎn)的gif不流暢实幕。
},false)