亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > HTML5 > 正文

canvas如何實現多張圖片編輯的圖片編輯器

2024-09-05 07:23:18
字體:
來源:轉載
供稿:網友

前言

圖片編輯器雖然是圖片涂鴉工具,但是在當前疫情的大背景下,該工具還可以成為老師在線修改學生提交的家庭作業的工具使用的,它可以極大地減輕了老師的批改作業的工作負擔,相信這軟件是有市場的。
本次不具體介紹canvas的各種操作畫布的api,而且相信大家在網上能搜到大量的關于canvas涂鴉的開源代碼,即使是這樣,我也相信真正把canvas涂鴉用于公司實際的項目的不多,改裝成圖片編輯器的會更少,而用于多張圖片編輯然后多張統一保存、上傳的更是寥寥無幾。下面,我將在我曾經寫過的一個canvas涂鴉的基礎上,將多張圖片編輯器的開發和思考過程記錄下來。

圖片編輯器產品需求

先說需求,由于涉及到實際公司的項目開發,滿足需求的圖片編輯器可能只是編輯一張單獨的圖片,可能是給你一個圖片列表也就是多張圖片的編輯,在用戶保存之前,用戶可以來回切換現在編輯哪張圖片,而且要記住每張照片的編輯操作,都要允許可以撤銷,最后統一點擊保存按鈕,沒有編輯過的圖片將被丟棄,已經編輯過的帶著涂鴉的圖片上傳給服務器。

準備工作,必須了解的相關知識點

html2canvas的使用

html2canvas這個插件實際是將網頁上的普通html元素轉化成canvas。那么為什么要將html元素轉化成canvas呢?那是因為canva具有許多html元素不具備的特點,例如可以在canvas上畫圖,畫線條等等操作,而且canvas直接提供api可以將畫布上展示的內容導成圖片。是不是有點類似于截圖,html2canvas就是利用這一點。 我最開始使用html2canvas時在公司h5項目有一個手寫板的項目。需要在是手寫板中簽字,然后將簽字之后的圖片導出然后上傳。后來又有一個在web端的圖片編輯器的項目,又用到了html2canvas這個插件,下面來介紹下該插件

介紹

html2canvas的缺點:

用html2canvas轉成的canvas,在最后生成的視覺效果上并不是100%還原原來的元素,也就是說會有部分像素點會丟失。

html2canvas的安裝

npm install html2canvas

html2canvas的引入

import html2canvas from 'html2canvas'

html2canvas的使用

如果一個帶圖片(無論是img標簽還是背景圖)的html元素在轉成canvas之后,該生成的canvas中img或者背景圖缺失,變成了白色的底,并且控制臺都告訴你圖片跨域了,解決方案如下:
以下第1條必須滿足,然后第2、3是根據是html元素是img標簽還是背景圖,來添加不同的配置項。

1.圖片服務器配置Access-Control-Allow-Origin 或使用代理
2.html2canvas的配置項中配置useCORS:true
3.img標簽增加 crossOrigin='anonymous'

html轉canvas,并且解決圖片跨域問題

html2canvas(dom, {  useCORS: true, // 背景圖片跨域  scale: window.devicePixelRatio,//像素比  width: dom.offsetWidth  height: dom.offsetHeight}).then(canvas => {  //得到base64  let base64 = canvas.toDateUrl() })

因為html2canvas將普通的html轉成了canvas,而canvas自帶將自身轉成的base64的方法,而base64格式文件可以直接作為img標簽的src,展示在頁面上

<img :src='base64' />

此時如果希望將生成的圖片上傳,base64是無法直接上傳的,需要將base64轉成blob格式。所以如下:我們將得到的base64數據傳進base64ToBlob函數,最后函數return的結果就是blob數據。請注意:該方法只是單純的將base64轉成blob的通用方法

base64轉blob

function base64ToBlob(base64){    var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);      while (n--) {        u8arr[n] = bstr.charCodeAt(n);      }      return (new Blob([u8arr], { type: mime }))}

其實canvas自帶將canas轉化成blob對象的方法

canvas轉blob

canvas.toBlob(file=>{    //此時file就是blob數據格式。    //成功上傳成blob之后需要為該blob數據添加name屬性,否則后面上傳到服務器會報錯:size not set    file.name = 'cover.png'})

但是在實際項目開發中遇到部分低版本的手機瀏覽器中的canvas元素不支持toBlob方法,報錯toBlob is not a function。所以此時我們需要對當前不支持canvas.toBlo方法的瀏覽器做polyfill

DOM canvas元素暴露了HTMLCanvasElement接口,該接口提供了用來操作一個canvas元素布局和呈現的屬性和方法HTMLCanvasElement接口繼承了element接口的屬性和方法。(來自MDN)

toBlob方法兼容性寫法

if (!HTMLCanvasElement.prototype.toBlob) {    Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {      value: function (callback, type, quality) {        var binStr = atob(this.toDataURL(type, quality).split(',')[1])        var len = binStr.length        var arr = new Uint8Array(len)        for (var i = 0; i < len; i++) {          arr[i] = binStr.charCodeAt(i)        }        callback(new Blob([arr], { type: type || 'image/png' }))     }    })}

以上代碼判斷當前瀏覽器HTMLCanvasElement.prototype內是否含有toBlob方法,如果沒有該方法,則為HTMLCanvasElement.prototype添加toBlob方法。
到目前為止,無論是base64直接轉成blob,還是canvas直接轉成blob,最后目的都是為了將blob數據上傳到服務器。請注意:當前頁面的blob數據是存儲在緩沖區的,而不是像電腦本地文件存儲在硬盤中上傳那樣,所以需要添加 isLocalFile:false屬性,fileData屬性接收一個數組,如果是一張圖片,則是個長度為1的,元素為blob格式的數組。上傳文件到服務器在這里不做介紹。

提交blob到服務器

// 轉完圖片數據,提交服務器    async upload (blobArr) {      const oss = await this.$uploadOSS.init({        fileData: blobArr,        isLocalFile: false,        onProgress: percent => {},        onSuccess: (res) => {          console.log(res)        }      })      if (oss) {        const data = await oss.start()        if (!data.code) {          this.$message.error(data.message)        }      }    },

以上是對html2canvas好和canvas的常見的屬性的介紹,同時也是開發圖片編輯器的前提。下面會一步步詳細介紹下在已有的canvas涂鴉板的基礎上的開發多張圖片編輯器的思路和過程。

基于canvas的圖片編輯器的怎么做?

1、既然要編輯圖片,自然要提供給我們的圖片的地址,可能是本地相對路徑,也可能是遠程地址,也可能是一張或者是多張圖片。所以進行操作的數據結構是數組,如果只有一張圖那就是長度為1的,元素為圖片地址的數組,另外需要解決圖片跨域來避免生成的圖片只有涂鴉部分,且背景白色、頭像或者圖片丟失的情況,上面已經提供了詳細的解決方案。

2、圖片編輯器肯定是個通用組件,所以根據父組件傳進來的圖片src的一個長度為length的數組,來填充一個相同長度的二維數組,二維數組中的元素記錄的是每一張圖片被編輯的歷史記錄的集合,也就是每一次操作canvas的時候生成的base64數據,在開始編輯之前初始化的時候該圖片默認填充空數組[],在這里介紹一個填充數組很好用的方法fill,值得注意:fill的內容如果是引用類型,會導致fill的每一項都是同一個引用,導致在操作其中一個元素時,其余所有的元素都一起改變。

//result:[[],[],...]this.canvasArrBase = Array(length).fill(0).map(item => {  return []})

2、點擊不同的圖片,將該圖片的src傳進編輯器組件,并將該src作為canvas背景圖,此時視覺上看到了一圖,在dom中其實是canvas的一張背景圖為src。
3、開始在頁面涂鴉畫布,為了避免無法在surface等觸控屏設備上使用畫布涂鴉或者圖片編輯器,請使用touch事件,而不是mouse事件。

 // 開始繪制  canvas.addEventListener('touchstart', e=> {    ...  },false)    // 繪制中  canvas.addEventListener('touchmove', e=>{   ...  },false)    // 結束繪制  canvas.addEventListener('touchend', e=>{    ...  },false)

4、在進入圖片編輯器之前將點擊的圖片的索引和圖片所在的圖片數組,一起作為props傳入圖片編輯器,記住當前在編輯第幾張圖片currentIndex,才能將涂鴉或者撤銷操作都記錄在這張圖片之上。當用戶在畫布上每操作一次,也就是開始touchstart,然后touchmove,最后touchend的時候,將當前的canvas畫布的內容(所有內容,不只是剛剛涂鴉的那一筆。類似于git的每一次提交,即使只是提交一行代碼,git也都會為整個項目生成一份快照,而不只是記錄本次修改的一行代碼,git回滾就是快照的回滾),包括這張背景圖片使用canvas.toDateUrl()生成base64,將其push進我們上面介紹的this.canvasArrBase[currenIndex]里,這時currenIndex所在數組的圖片多了一張歷史記錄,也就是剛剛涂鴉的畫面被我們保存下來了。這也就是canvas圖片編輯器,撤銷的基礎,有了它我們才知道撤銷之后展示什么。

//新的土涂鴉操作生成的快照存儲在當前索引的數組內 this.canvasArrBase[this.currentIdex].push(canvas.toDataUrl())

5、切換圖片也就意味著改變了canvas的背景圖,改變了currentIndex,然后在新的currentIndex上對另外一張圖片進行編輯,其實也是同樣的步驟,無非就是往當前編輯的圖片的push畫布剛剛展示的所有內容。
6、重點來了,撤銷如何做呢?如何撤銷,如何在畫布上一步步撤銷并且看到上一次,上上次的繪畫記錄呢?
隨著每張圖片的編輯,每張圖片產生一些歷史記錄,我們就是利用這些歷史記錄的來進行回滾撤銷操作的。當我們在當前已經編輯過的圖片中點一次撤銷的時候,我們需要將上次canvas中展示的畫布內容畫到當前的畫布中。在撤銷的時候可以直接將我們存儲的數據源直接刪掉,所以只需要利用 canvas.drawImage() 方法,將需要展示的那一條記錄畫到canvas畫布中即可。

drawImage方法有很多參數,用法點擊查看詳情

let newBaseArr = this.canvasArrBase[this.currentIdex]let { offsetWidth: canvasWidth, offsetHeight: canvasHeight } = canvas//生成一張新的圖片let image = new Image()//圖片的src賦值成當前需要展示的base64的值(也就是讓用戶看到撤銷后的畫面)image.src = this.canvasArrBase[this.currentIdex][newBaseArr.length-1]//給img的src賦值后,使用onload監聽加載圖片情況,加載完成后再繪制,不加onload就極可能繪制失敗。image.onload = function () {    canvas.drawImage(image, 0, 0, canvasWidth, canvasHeight)}

7、關于性能優化:由于你根本不知道用戶會拿多么大的圖片來進行編輯,所以如果有9張圖片,每張圖片都編輯10次,那么存在內存中的base64數據量就會非常龐大,在進行頁面切換或者圖片涂鴉歷史撤銷的時候就可能造成頁面的卡頓,為了避免這種情況,在切換圖片之前,我只會存儲當前圖片最后一張圖片的base64。
8、提交,保存之前判斷this.canvasArrBase中每一項的長度,大于0,則是有編輯過,否則被過濾掉。然后利用前面介紹上傳方法上傳到服務器,就OK啦!

總結

在學習canvas的道路上它總能給我帶來一些驚喜和驚訝,一些我們熟知的工具,例如:echart,高德地圖等無一不是基于canvas做出的。我曾經有位同事是一位echart圖表大神,受他的影響,我逐漸對echart的威力有所領略,希望在這樣一個開源社區里和大家一起學習,進步。

到此這篇關于canvas如何實現多張圖片編輯的圖片編輯器的文章就介紹到這了,更多相關canvas圖片編輯器內容請搜索武林網以前的文章或繼續瀏覽下面的相關文章,希望大家以后多多支持武林網!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
热re99久久精品国产66热| 成人午夜激情网| 欧美成人精品一区| 国产98色在线| 亚洲精品99久久久久中文字幕| 亚洲综合精品一区二区| 国产精品爽爽ⅴa在线观看| 热久久99这里有精品| 91精品国产电影| 国产精品高潮呻吟久久av无限| 亚洲第一页中文字幕| 国精产品一区一区三区有限在线| 欧美激情精品久久久久久变态| 日韩在线观看高清| 九九综合九九综合| 97视频网站入口| 亚洲国产免费av| 国产xxx69麻豆国语对白| 国产精品一区二区三区免费视频| 欧美在线视频免费观看| 国产97人人超碰caoprom| 国产成人精品a视频一区www| 亚洲免费电影在线观看| 91av视频导航| 97超级碰在线看视频免费在线看| 亚洲九九九在线观看| 午夜美女久久久久爽久久| 日韩av网站电影| 成人激情av在线| 97国产真实伦对白精彩视频8| 亚洲精品自在久久| 国产精品在线看| 国产精品视频永久免费播放| 亚洲色图35p| 性亚洲最疯狂xxxx高清| 久久精彩免费视频| 欧美精品久久久久a| 国产成人精品视频在线观看| 欧美夫妻性视频| 亚洲性夜色噜噜噜7777| 亚洲精品国产精品国产自| 欧美超级乱淫片喷水| 国产精品黄色av| 久久影视电视剧免费网站清宫辞电视| 亚洲www在线| 欧美午夜精品伦理| 亚洲人精品午夜在线观看| 成人午夜在线影院| 91免费在线视频网站| 欧美成人中文字幕在线| 亚洲欧美激情视频| 国产精品久久久久久久久| 欧美电影免费观看高清| 亚洲国产精品国自产拍av秋霞| 日韩av不卡在线| 97在线视频一区| 国产精品自产拍在线观看中文| 亚洲va欧美va在线观看| 亚洲精品小视频| 亚洲精美色品网站| 国产精品美女在线观看| 亚洲成人激情图| 日本亚洲欧洲色| 一区二区三区在线播放欧美| 亚洲精品中文字幕女同| 亚洲精品日韩欧美| 亚洲加勒比久久88色综合| 亚洲第一中文字幕| 久久久国产精品亚洲一区| 欧美乱妇40p| 91亚洲永久免费精品| 久久久www成人免费精品张筱雨| 欧美成人中文字幕| 欧美日韩裸体免费视频| 亚洲自拍偷拍区| 青青草原一区二区| 国产一区二区av| 日韩欧美在线免费观看| 欧美极品少妇xxxxx| 日韩经典一区二区三区| 亚洲成人动漫在线播放| 日韩中文字幕国产精品| 国产噜噜噜噜噜久久久久久久久| 色噜噜久久综合伊人一本| y97精品国产97久久久久久| 欧美成人午夜激情视频| 欧美一级片一区| 久久久国产一区二区| 91在线观看免费观看| 日本久久久久久久久久久| 久久不射热爱视频精品| 狠狠躁天天躁日日躁欧美| 欧美国产日韩中文字幕在线| 国产成人在线亚洲欧美| 欧美一级淫片videoshd| 欧美电影在线观看| 精品国产一区二区三区在线观看| 国产综合久久久久| 2019最新中文字幕| 久久久免费精品视频| 日韩美女在线播放| 亚洲欧美日韩高清| 成人女保姆的销魂服务| 国色天香2019中文字幕在线观看| 欧美专区日韩视频| 97人人模人人爽人人喊中文字| 日本一区二区在线免费播放| 国产91精品久久久| 亚洲黄色在线看| 性亚洲最疯狂xxxx高清| 国产精品福利片| 国产精品99蜜臀久久不卡二区| 成人黄色av网| 国产精品视频在线播放| 久久精品亚洲一区| 亚洲国产精品va在线看黑人动漫| 亚洲经典中文字幕| 国产又爽又黄的激情精品视频| 91啪国产在线| 久久伊人色综合| 久久久久久久久久久免费精品| 久久6精品影院| 91欧美精品午夜性色福利在线| 国产不卡视频在线| 国产一区二区三区视频| 欧美日本高清一区| 欧美有码在线观看视频| 欧美成人精品一区二区| 日韩av在线电影网| 97精品视频在线播放| 日韩成人在线视频网站| 色婷婷av一区二区三区久久| 亚洲精品国产精品自产a区红杏吧| 国产精品99久久久久久白浆小说| 亚洲一区二区三区四区视频| 欧美成人精品在线观看| 第一福利永久视频精品| 亚洲天堂av综合网| 中文字幕精品在线| 久久国产精品久久久久久| 中国china体内裑精亚洲片| 久久视频这里只有精品| 亚洲一区二区三| 一区二区三区无码高清视频| 国产精品露脸av在线| 91中文字幕在线| 91色p视频在线| 日韩成人在线视频| 尤物tv国产一区| 高清视频欧美一级| 亚洲免费视频在线观看| 日韩av电影免费观看高清| 日韩欧美主播在线| 98精品国产高清在线xxxx天堂| 粉嫩av一区二区三区免费野| 久久国内精品一国内精品| 国产精自产拍久久久久久蜜| 一区二区三区美女xx视频| 欧美日韩国产成人| 亚洲最大成人在线| 国产精品海角社区在线观看| 欧美床上激情在线观看| 日韩免费观看av| 久久精品国产一区二区三区|