溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

canvas.toDataURL在iOS運(yùn)行失敗怎么辦

發(fā)布時(shí)間:2021-05-18 15:13:26 來(lái)源:億速云 閱讀:304 作者:小新 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)canvas.toDataURL在iOS運(yùn)行失敗怎么辦,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

最近做了一個(gè)海報(bào)生成的組件,需要drawimage到畫布上,image來(lái)源包括本地和異地的圖片src;
首先講一點(diǎn),異地圖片如果不設(shè)置允許跨域訪問(wèn),canvas.toDataURL是無(wú)法畫image的,報(bào)畫布污染的錯(cuò);首先放一張我要生成的圖;

canvas.toDataURL在iOS運(yùn)行失敗怎么辦

上面加載了兩張本地圖片,兩張異地圖片,寫了一些文字;在windows谷歌瀏覽器跑是好的,是吧,圖片畫出來(lái),感覺無(wú)壓力;用安卓也是好的,很開心;可是到IOS手機(jī)上,我去,怎么圖片顯示不出來(lái)啊,然后
try catch 錯(cuò)誤,沒啥有用的信息;

try {
 // 將canvas對(duì)象轉(zhuǎn)化為image/png
   var dataUrl = canvas.toDataURL('image/png')
 } catch (err) {
   console.log(err)
 }

我擦,這怎么辦???
然后去cnbing搜,好多相同問(wèn)題,好多原因,有個(gè)老外說(shuō)動(dòng)態(tài)更改canvas寬高無(wú)法再ios畫出圖片;還有的人說(shuō):
圖片文件 size 太大,是否圖片超過(guò)了 3M ? -----------我看了下生成的圖片才幾百kb PASS

圖片的 dimension 太大,是否圖片尺寸超過(guò)了 1000 x 1000 像素?我的尺寸確實(shí)超過(guò)了,寬高都超了,然而測(cè)試了下小的寬高,照舊ios畫不出來(lái)啊~~~PASS

你指定的 mime_type 不支持,你用的是哪個(gè) mime type?—canvas的 toDataURL API我看過(guò)了,可以支持三個(gè)類型,各試了一遍,無(wú)果 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">長(zhǎng)安按海報(bào)發(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對(duì)象
    }
  },
  mounted () {
    this.initCanvas()
  },
  methods: {
    /**
     * 隱藏海報(bào)
     */
    hidePoster () {
      this.$emit('hide')
    },
    /**
     * 加載圖片
     * @param {Object} img 圖片地址
     * @return {Promise} img dom
     */
    loadImage (img) {
      return new Promise((resolve, reject) => {
        // image dom 對(duì)象
        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實(shí)例
      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('我就是個(gè)我就賬號(hào)賬號(hào)', 147 * 2, 278 * 2, 290 * 2, '#333333', '32px PingFangSC-Regular ')
        this.drawText('榮譽(yù)稱號(hào)是我', 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('快來(lái)助我沖榜贏紅燒醬油吧', 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á)沖榜活動(dòng)', 180 * 2, 463 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
        this.drawText('邀請(qǐng)好友跟你一起沖大獎(jiǎng)', 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對(duì)象
      let canvas = this.$refs.canvas

      try {
        // 將canvas對(duì)象轉(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,就是下面這個(gè)function

 /**
     * 加載圖片
     * @param {Object} img 圖片地址
     * @return {Promise} img dom
     */
    loadImage (img) {
      return new Promise((resolve, reject) => {
        // image dom 對(duì)象
        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確實(shí)要這么做;
大家如果對(duì) crossorigin 有疑問(wèn)可以看一下MDN對(duì)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)于“canvas.toDataURL在iOS運(yùn)行失敗怎么辦”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI