您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關canvas.toDataURL在iOS運行失敗怎么辦,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
最近做了一個海報生成的組件,需要drawimage到畫布上,image來源包括本地和異地的圖片src;
首先講一點,異地圖片如果不設置允許跨域訪問,canvas.toDataURL是無法畫image的,報畫布污染的錯;首先放一張我要生成的圖;
上面加載了兩張本地圖片,兩張異地圖片,寫了一些文字;在windows谷歌瀏覽器跑是好的,是吧,圖片畫出來,感覺無壓力;用安卓也是好的,很開心;可是到IOS手機上,我去,怎么圖片顯示不出來啊,然后
try catch 錯誤,沒啥有用的信息;
try { // 將canvas對象轉化為image/png var dataUrl = canvas.toDataURL('image/png') } catch (err) { console.log(err) }
我擦,這怎么辦???
然后去cnbing搜,好多相同問題,好多原因,有個老外說動態更改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">長安按海報發送給朋友</p> </div> </template>
<script> export default { data () { // 參數 const u = navigator.userAgent // ios終端 const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios終端 return { // 返回參數 localUrl: isIOS ? location.href.split('#')[0] : location.href, // 當前路徑 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函數 */ 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://s3-011-shinho-syj-uat-bjs.s3.cn-north-1.amazonaws.com.cn/mall/2019_06/border04.png', isCross_domain: true }, { url: 'https://s3-011-shinho-syj-uat-bjs.s3.cn-north-1.amazonaws.com.cn/mall/2019_06/132.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('直達沖榜活動', 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軸坐標 * @param {Number} y y軸坐標 * @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對象轉化為image/png var dataUrl = canvas.toDataURL('image/png') } catch (err) { console.log(err) } // 創建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屬性之前賦值
盡管沒有找到準確的文檔明確指定crossOrigin屬性必須在src屬性之前賦值,但是要適配IOS確實要這么做;
大家如果對 crossorigin 有疑問可以看一下MDN對crossorigin的解釋:
https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image
里面講了畫布的污染和解決方法,就是設置 crossorigin = “Anonymous”;里面的方法也是先設置crossorigin在圖片加載完后設置 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; }
關于“canvas.toDataURL在iOS運行失敗怎么辦”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。