因爲一些簡單的圖片拼合須要處理(大概8000張),可是又沒有找到合適的傻瓜軟件可以很好地解決需求,同時也很使人頭疼的是nodejs裏面圖片處理庫,基本上沒幾個好用,且安裝費時費勁 (固然我仍是裝了)。做爲一個有追求的前端,若是能不依靠其餘的東西,直接在前端頁面上實現它不香麼?因而就有了這個小嚐試。其實很是簡單,僅以此文記錄一下,怕之後不用忘記。前端
1.因爲canvas的安全限制,咱們必須保證資源和網頁在同一個域名下進行,不然畫入是沒問題的,可是導出就會報「畫布被污染」的錯誤。因此咱們一共有多個解決辦法:node
img.setAttribute('crossOrigin', 'anonymous')
。特色:能解決目前的問題,可是有隱患URL.revokeObjectURL
取消掉關聯,其餘沒發現缺點。以上是我我的探索的五種解決辦法,分別適合不一樣場景下的需求。chrome
前兩種例子不便於展現,直接下面是三種辦法的對應代碼例子:canvas
let can = document.getElementById('canvas');
let ctx = can.getContext('2d');
fetch('https://img.alicdn.com/bao/uploaded/i1/446338500/O1CN01npzdZ52Cf3A4cx8JG_!!0-item_pic.jpg_240x240.jpg').then(
res => res.blob())
.then(res => {
let fr = new FileReader();
fr.onload = function (e) {
console.log(e)
console.log(e.target.result)
let img = new Image();
//第一種辦法
// img.setAttribute('crossOrigin', 'anonymous');
// img.src =
// 'https://img.alicdn.com/bao/uploaded/i1/446338500/O1CN01npzdZ52Cf3A4cx8JG_!!0-item_pic.jpg_240x240.jpg'
//第二種辦法
// img.src = e.target.result; //轉成base64
//第三種辦法
// img.src = URL.createObjectURL(res);//轉成Blob地址ObjectUrl
img.onload = function () {
ctx.drawImage(img, 0, 0)
console.log(can.toDataURL())//導出成dataurl
// canvas.toBlob(function (blob) {//導出成blob地址
// var url = URL.createObjectURL(blob);
// console.log(url)
// });
}
}
fr.onerror = function () {
console.log('讀取錯誤!')
}
fr.readAsDataURL(res)
})
複製代碼
有了以前的前奏流程,接下來咱們能夠開始實現下載,利用a標籤的download便可。同時要注意,a標籤download屬性不支持跨域,不過在咱們這裏面,不會涉及到跨域(canvas數據就是從這頁面裏產生的)。跨域
如何批量導出?promise
在這裏要注意,因爲咱們存在一些異步環節,咱們要使用Async await來實現對它們的順序執行。這樣的話,就會按照順序執行,另外瀏覽器記得打開容許自動下載(本地環境可能會老有提示,可是若是拿一個localhost託管就不會有問題了)瀏覽器
例子:安全
(async () => {
let result = []
let arr = []
for (let i = 0; i < arr.length; i++) {
await new Promise((res, rej) => {
setTimeout(() => {
res()
}, 10)
})
try {
await createImg(arr[i]).catch(err => {
result.push(arr[i])
console.log(arr[i], '服務器端響應出錯,沒法獲取圖片')
})
} catch (e) {
result.push(arr[i])
console.log(arr[i], '程序處理時沒法處理圖片', '緣由:', e)
}
}
document.body.innerText = result.join("")
})()
function createImg(article) {
return new Promise((res, rej) => {
let temp = new Image()
temp.src = 'http://XXXXXX/getpic?type=touming&article=' + article;
temp.onerror = function () {
rej(article)
}
temp.onload = function () {
ctx.drawImage(temp, 940, 90, 650, 650);
var bloburl = canvas.toDataURL('image/jpeg');
var anchor = document.createElement('a');
anchor.href = bloburl;
anchor.download = article;
anchor.click()
ctx.rect(0, 0, 2000, 800);
ctx.fillStyle = "rgb(236,237,239)";
ctx.fill();
res()
}
})
}
複製代碼
踩坑:服務器
這裏要注意,我定義了Image對象的onerror事件,由於async await等待的Promise不知道捕獲到服務器錯誤的(若是服務器宕機了一下,腳本會直接中止報錯),因此咱們須要在onerror裏面引入,而後reject掉,promise就能夠拿到錯誤信息了,以後再catch就行了。同時爲了防止出現複雜的報錯中止,加入了try catch保證錯誤能被拿到。異步