1.canvas、img、video,都是圖像對象,屬於圖像類型的節點。這種圖像對象不是Image 對象,而是對加載圖像數據流的節點的統稱。javascript
2.圖像對象的數據的讀寫php
讀取圖像數據html
寫入圖像數據前端
canvas 讀取img 圖像的案例: https://www.runoob.com/try/tr...
canvas 讀取video 圖像的案例: https://www.w3school.com.cn/t...vue
3.gif 是介於圖片和視頻之間的特殊存在。html5
直接繪製gif 確定是很差使的java
<div> <img id="img" src="./assets/images/girl.gif"> </div> <canvas id="c" width="300" height="212"></canvas> <script> const img=document.getElementById("img"); const c=document.getElementById("c"); const ctx=c.getContext('2d'); ctx.drawImage(img,0,0); </script>
利用requestAnimationFrame,頻繁繪製,也很差使git
const img=document.getElementById("img"); const c=document.getElementById("c"); const ctx=c.getContext('2d'); render(); function render(){ ctx.drawImage(img,0,0); window.requestAnimationFrame(render); }
<video src="./assets/images/girl.gif"></video>
1.獲取gif 數據github
let xhr=new XMLHttpRequest(); xhr.open('get','./assets/images/zao.gif'); xhr.setRequestHeader("Content-Type", "text/plain"); xhr.send(); xhr.onreadystatechange=function(){ if(xhr.readyState===4){ if(xhr.status===200){ console.log('response',xhr.response); } } }
2.從response 中提取gif 數據,並解析成ImageData 對象的集合canvas
3.用canvas 上下文的putImageData 方法,將ImageData 數據加載到canvas 中
具體實現方式我就不說了,有點複雜,不是一時片刻能說完的(真正緣由是我研究了半天libgif.js源碼,仍是隻看懂了大概流程)。先知道這個原理吧,libgif.js 庫就是實現這塊功能的。
libgif.js已經完成了對gif 的解析,並將其寫入了canvas 中。
libgif.js網址:https://github.com/buzzfeed/l...
下面是我從官網上覆制粘貼下來,用百度翻譯一下 ,而後略做調整。英語好的能夠跳過這裏,看官網。
1.寫在圖片標籤裏的屬性 Image tag attributes
2.構造函數 Constructor options
3.loading 事件
4.播放控制器 play controls
5.數據獲取 getters
6.官方案例
<div> <img id="img1" src="./assets/images/zao.gif" rel:auto_play="1" rel:rubbable="1" > </div> <div> <img id="img2" src="./assets/images/zao.jpg" rel:animated_src="./assets/images/zao.gif" rel:auto_play="0" /> </div> <div> <a href="javascript:;" onmousedown="sup2.pause(); return false;">Pause</a> | <a href="javascript:;" onmousedown="sup2.play(); return false;">Play</a> | <a href="javascript:;" onmousedown="sup2.move_to(0); return false;">Restart</a> | <a href="javascript:;" onmousedown="sup2.move_relative(1); return false;">Step forward</a> | <a href="javascript:;" onmousedown="sup2.move_relative(-1); return false;">Step back</a> </div> <canvas id="c" width="300" height="212"></canvas> <script src="./lib/libgif.js"></script> <script src="./lib/rubbable.js"></script> <script> let img1=document.getElementById("img1"); let img2=document.getElementById("img2"); let sup1 = new RubbableGif({ gif: img1 } ); sup1.load(); let sup2 = new SuperGif({ gif: img2 } ); sup2.load(); </script>
注:
實際項目中,咱們可能只是想在咱們的canvas 項目裏添加動起來表情包,而不是額外的創建一個真實的img 節點,更不是再生成一個真實的canvas 將其替換。因此,我作了一下調整:
1.將rubbable.js 中替換img 節點的方法過濾掉。爲何叫過濾呢,由於這樣不會影響原始功能,尊重做者。
if(parent){ parent.insertBefore(div, gif); parent.removeChild(gif); }
2.引用Image 對象代替真實的<img> 節點,這樣就不須要再讓瀏覽器渲染img 了,節省資源,真正只將其當成一個傳遞數據的工具。
const gif=new Image(w,h); gif.setAttribute('data-animated_src',src);
3.爲SuperGif 添加一個change 屬性的方法,讓其在圖片渲染時執行。這樣就能夠在外部,實時獲取SuperGif 裏的canvas。注意,這種寫法不會影響對象的繼承,由於SuperGif 還有各個叫RubbableGif 的子級,SuperGif 實例對其原型屬性修改後,RubbableGif 的實例也會繼承這種修改。這個問題也能夠從繼承上解決,我本着尊重做者的目的,就不改了(其實是看得費勁,不想深究了)。
(function (root, factory) { //... }(this, function () { //渲染監聽方法 var change=function(){} var SuperGif = function ( opts ) { //... var player = (function () { //... var putFrame = function () { //... if(options.change){options.change()} } } } })
4.還有的小問題,libgif.js 對標籤屬性的定義不規範。rel:auto_play="0" ,這樣的方式定義在模板文件裏還能夠,好比vue的v-on:click="play()"。在真正的HTML 要這樣的寫:data-auto_play="0"
六,canvas 顯示圖片
1.canvas顯示圖片的方式有兩種:
canvas 繪圖:
參考地址: https://www.runoob.com/try/tr...
2.上代碼:
項目地址:https://github.com/buglas/fun...,中的gif4.html 文件
<div> <canvas id="canvas" width="300" height="212"></canvas> </div> <script src="./lib/libgif.js"></script> <script src="./lib/rubbable.js"></script> <script> const canvas=document.getElementById('canvas'); const ctx=canvas.getContext('2d'); const src='./assets/images/girl.gif'; const [w,h]=[150,133]; const GifTool={ drawGif:({src,w,h,draw})=>{ const gif=new Image(w,h); gif.setAttribute('data-animated_src',src); const sup = new SuperGif({ gif, change:()=>{ const canvas=sup.get_canvas(); const curCtx=canvas.getContext("2d"); const imgData=curCtx.getImageData(0,0,w,h); draw({imgData,canvas}); } }); sup.load(); } } GifTool.drawGif({ src,w,h, draw:({imgData})=>{ ctx.putImageData(imgData,0,0); } }); </script>
GifTool.drawGif({ src,w,h, draw:({canvas})=>{ const pat=ctx.createPattern(canvas,"repeat"); ctx.rect(0,0,w,h); ctx.fillStyle=pat; ctx.fill(); } });
GifTool.drawGif({ src,w,h, draw:({canvas})=>{ const pat=ctx.createPattern(canvas,"repeat"); ctx.save(); ctx.translate(10,0); ctx.beginPath(); ctx.arc(60,80,60,0,Math.PI*2); ctx.fillStyle=pat; ctx.fill(); ctx.restore(); ctx.save(); ctx.translate(150,40); ctx.beginPath(); ctx.arc(60,80,60,0,Math.PI*2); ctx.fillStyle=pat; ctx.fill(); ctx.restore(); } });