這篇文章主要介紹了關(guān)于canvas.toDataURL 在iOS運行失敗的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
最近做了一個海報生成的組件,需要drawimage到畫布上,image來源包括本地和異地的圖片src;
首先講一點,異地圖片如果不設(shè)置允許跨域訪問,canvas.toDataURL是無法畫image的,報畫布污染的錯;首先放一張我要生成的圖;
上面加載了兩張本地圖片,兩張異地圖片,寫了一些文字;在windows谷歌瀏覽器跑是好的,是吧,圖片畫出來,感覺無壓力;用安卓也是好的,很開心;可是到IOS手機(jī)上,我去,怎么圖片顯示不出來啊,然后
try catch 錯誤,沒啥有用的信息;
try {
// 將canvas對象轉(zhuǎn)化為image/png
var dataUrl = canvas.toDataURL('image/png')
} catch (err) {
console.log(err)
}
我擦,這怎么辦???
然后去cnbing搜,好多相同問題,好多原因,有個老外說動態(tài)更改canvas寬高無法再ios畫出圖片;還有的人說:
圖片文件 size 太大,是否圖片超過了 3M ? -----------我看了下生成的圖片才幾百kb PASS
圖片的 dimension 太大,是否圖片尺寸超過了 1000 x 1000 像素?我的尺寸確實超過了,寬高都超了,然而測試了下小的寬高,照舊ios畫不出來啊~~~PASS
你指定的 mime_type 不支持,你用的是哪個 mime type?—canvas的 toDataURL API我看過了,可以支持三個類型,各試了一遍,無果 PASS
先上我的代碼:
<template>
<div id="Poster">
<div class="mask" @click="hidePoster()"></div>
<canvas ref="canvas" width="588" height="1044" style="display:none;"></canvas>
<div ref="box" id="Poster-box" @click.stop>
<span class="close" @click="hidePoster()"></span>
</div>
<p class="tip">長安按海報發(fā)送給朋友</p>
</div>
</template>
<script>
export default {
data () { // 參數(shù)
const u = navigator.userAgent // ios終端
const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios終端
return { // 返回參數(shù)
localUrl: isIOS ? location.href.split('#')[0] : location.href, // 當(dāng)前路徑
canvas: Object // canvas對象
}
},
mounted () {
this.initCanvas()
},
methods: {
/**
* 隱藏海報
*/
hidePoster () {
this.$emit('hide')
},
/**
* 加載圖片
* @param {Object} img 圖片地址
* @return {Promise} img dom
*/
loadImage (img) {
return new Promise((resolve, reject) => {
// image dom 對象
const $image = document.createElement('img')
if (img.isCross_domain) {
console.log(img.url)
$image.setAttribute('crossOrigin', 'Anonymous')
}
$image.onload = () => {
resolve($image)
}
$image.src = img.url
$image.onerror = reject
})
},
/**
* init初始化canvas函數(shù)
*/
async initCanvas () {
// 獲取vue實例
var vm = this
vm.$indicator.open({
text: '加載中...',
spinnerType: 'fading-circle'
})
this.canvas = this.$refs.canvas.getContext('2d')
this.canvas.height = 400
this.canvas.width = 300
this.canvas.fillStyle = '#ffffff'
this.canvas.fillRect(0, 0, 588, 1044)
// image urls
const imgArr = [
{
url: require('../assets/poster-banner.png'),
isCross_domain: false
},
{
url: require('../assets/shadow.png'),
isCross_domain: false
},
{
url: 'https://a5img.pncdn.cn/2020/1027/1603776310363.png',
isCross_domain: true
},
{
url: 'https://a5img.pncdn.cn/2020/1027/1603776310950.jpg',
isCross_domain: true
}
]
// image doms
await Promise.all(imgArr.map(img => this.loadImage(img))).then((imgs) => {
console.log('done')
this.canvas.drawImage(imgs[0], 0, 0, 588, 216 * 2)
this.canvas.drawImage(imgs[1], 97 * 2, 166 * 2, 100 * 2, 100 * 2)
this.canvas.save()
this.canvas.beginPath()
this.canvas.arc(147 * 2, 214 * 2, 34 * 2, 0, 2 * Math.PI, false)
this.canvas.clip()
this.canvas.drawImage(imgs[2], 113 * 2, 180 * 2, 68 * 2, 68 * 2)
this.canvas.restore()
this.canvas.drawImage(imgs[3], 189 * 2, 409 * 2, 88 * 2, 88 * 2)
// 繪制文字
this.drawText('我就是個我就賬號賬號', 147 * 2, 278 * 2, 290 * 2, '#333333', '32px PingFangSC-Regular ')
this.drawText('榮譽稱號是我', 147 * 2, 300 * 2, 290 * 2, '#999999', '26px PingFangSC-Regular ')
this.drawText('距離沖榜還差10人', 147 * 2, 340 * 2, 290 * 2, '#FA6F5B', 'bold 36px arial')
this.drawText('快來助我沖榜贏紅燒醬油吧', 147 * 2, 370 * 2, 290 * 2, '#FA6F5B', 'bold 36px arial ')
this.drawText('掃描二維碼', 180 * 2, 443 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
this.drawText('直達(dá)沖榜活動', 180 * 2, 463 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
this.drawText('邀請好友跟你一起沖大獎', 180 * 2, 483 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
this.showPic()
vm.$indicator.close()
})
},
/**
* 繪制文字
* @param {String} title 文字名稱
* @param {Number} x x軸坐標(biāo)
* @param {Number} y y軸坐標(biāo)
* @param {Number} maxwidth 最大寬度
* @param {String} color 顏色
* @param {String} font 字體樣式
* @param {String} textalign 文字排版
*/
drawText (title, x, y, maxwidth, color, font, textalign = 'center') {
this.canvas.font = font
this.canvas.textAlign = textalign
this.canvas.fillStyle = color
this.canvas.fillText(title, x, y, maxwidth)
},
/**
* 顯示圖片
*/
showPic () {
// 獲取canvas對象
let canvas = this.$refs.canvas
try {
// 將canvas對象轉(zhuǎn)化為image/png
var dataUrl = canvas.toDataURL('image/png')
} catch (err) {
console.log(err)
}
// 創(chuàng)建img 元素
var newImg = document.createElement('img')
newImg.src = dataUrl
newImg.style.width = '100%'
newImg.style.height = '100%'
newImg.className = 'img-poster'
newImg.style.borderRadius = '8px'
this.$refs.box.appendChild(newImg)
}
}
}
</script>
盤查了好久,最后找到bug,就是下面這個function
/**
* 加載圖片
* @param {Object} img 圖片地址
* @return {Promise} img dom
*/
loadImage (img) {
return new Promise((resolve, reject) => {
// image dom 對象
const $image = document.createElement('img')
$image.src = img.url
if (img.isCross_domain) {
console.log(img.url)
$image.setAttribute('crossOrigin', 'Anonymous')
}
$image.onload = () => {
resolve($image)
}
$image.onerror = reject
})
},
有沒有注意到crossOrigin屬性是在src屬性之后賦值的;/(ㄒoㄒ)/~~
crossOrigin屬性必須在src屬性之前賦值
crossOrigin屬性必須在src屬性之前賦值
crossOrigin屬性必須在src屬性之前賦值
盡管沒有找到準(zhǔn)確的文檔明確指定crossOrigin屬性必須在src屬性之前賦值,但是要適配IOS確實要這么做;
大家如果對 crossorigin 有疑問可以看一下MDN對crossorigin的解釋:
https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image
里面講了畫布的污染和解決方法,就是設(shè)置 crossorigin = “Anonymous”;里面的方法也是先設(shè)置crossorigin在圖片加載完后設(shè)置 src;
如下
var img = new Image,
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
src = "http://example.com/image"; // insert image url here
img.crossOrigin = "Anonymous";
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage( img, 0, 0 );
localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
到此這篇關(guān)于關(guān)于canvas.toDataURL 在iOS運行失敗的問題解決 的文章就介紹到這了,更多相關(guān)canvas.toDataURL在iOS運行失敗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!
來源:腳本之家
鏈接:https://www.jb51.net/html5/745320.html
申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!