关于canvas.toDataURL 在iOS运行失败的问题解决


Posted in HTML / CSS onSeptember 16, 2020

最近做了一个海报生成的组件,需要drawimage到画布上,image来源包括本地和异地的图片src;
首先讲一点,异地图片如果不设置允许跨域访问,canvas.toDataURL是无法画image的,报画布污染的错;首先放一张我要生成的图;

关于canvas.toDataURL 在iOS运行失败的问题解决

上面加载了两张本地图片,两张异地图片,写了一些文字;在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运行失败的问题解决 的文章就介绍到这了,更多相关canvas.toDataURL在iOS运行失败内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

HTML / CSS 相关文章推荐
IE下实现类似CSS3 text-shadow文字阴影的几种方法
May 11 HTML / CSS
CSS3的column-fill属性对齐列内容高度的用法详解
Jul 01 HTML / CSS
CSS3中伪元素::before和::after的用法示例
Sep 18 HTML / CSS
解决margin 外边距合并问题
Jul 03 HTML / CSS
CSS3实现歌词进度文字颜色填充变化动态效果的思路详解
Jun 02 HTML / CSS
HTML5 FormData 方法介绍以及实现文件上传示例
Sep 12 HTML / CSS
html5触摸事件判断滑动方向的实现
Jun 05 HTML / CSS
HTML5 Canvas的性能提高技巧经验分享
Jul 02 HTML / CSS
HTML5 canvas绘制的玫瑰花效果
May 29 HTML / CSS
浅谈html5标签css3的常用样式
Oct 20 HTML / CSS
浅谈html5之sse服务器发送事件EventSource介绍
Aug 28 HTML / CSS
HTML基础-标签分类(闭合标签,空标签,块级元素,行内元素,行级块元素,可替换元素)
Mar 31 HTML / CSS
canvas绘制图片drawImage使用方法
Sep 15 #HTML / CSS
HTML5中外部浏览器唤起微信分享功能的代码
Sep 15 #HTML / CSS
浅析HTML5 Landmark
Sep 11 #HTML / CSS
详解HTML5中CSS外观属性
Sep 10 #HTML / CSS
详解如何在登录过期后跳出Ifram框架
Sep 10 #HTML / CSS
HTML5中input输入框默认提示文字向左向右移动的示例代码
Sep 10 #HTML / CSS
HTML5输入框下拉菜单功能的示例代码
Sep 08 #HTML / CSS
You might like
php中echo()和print()、require()和include()等易混淆函数的区别
2012/02/22 PHP
ThinkPHP CURD方法之data方法详解
2014/06/18 PHP
xmlHTTP实例
2006/10/24 Javascript
javascript 异常处理使用总结
2009/06/21 Javascript
ie focus bug 解决方法
2009/09/03 Javascript
JavaScript prototype对象的属性说明
2010/03/13 Javascript
js parseInt(&quot;08&quot;)未指定进位制问题
2010/06/19 Javascript
原创javascript小游戏实现代码
2010/08/19 Javascript
用JS提交参数创建form表单在FireFox中遇到的问题
2013/01/16 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
JS图片自动轮换效果实现思路附截图
2014/04/30 Javascript
简介JavaScript中的getUTCFullYear()方法的使用
2015/06/10 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
2016/08/11 Javascript
javascript汉字拼音互转的简单实例
2016/10/09 Javascript
js实现无缝滚动图
2017/02/22 Javascript
如何正确理解javascript的模块化
2017/03/02 Javascript
详解webpack介绍&amp;安装&amp;常用命令
2017/06/29 Javascript
使用prop解决一个checkbox选中后再次选中失效的问题
2017/07/05 Javascript
详解微信小程序实现仿微信聊天界面(各种细节处理)
2019/02/17 Javascript
vue使用codemirror的两种用法
2019/08/27 Javascript
在vue中利用全局路由钩子给url统一添加公共参数的例子
2019/11/01 Javascript
Vue如何跨组件传递Slot的实现
2020/12/14 Vue.js
Python脚本实现12306火车票查询系统
2016/09/30 Python
安装python依赖包psycopg2来调用postgresql的操作
2021/01/01 Python
Python截图并保存的具体实例
2021/01/14 Python
幼儿园教师获奖感言
2014/03/11 职场文书
2014年入党积极分子党校培训心得体会
2014/07/08 职场文书
社会发展项目建议书
2014/08/25 职场文书
单位法定代表人授权委托书
2014/09/20 职场文书
大学拉赞助协议书范文
2014/09/26 职场文书
2014企业年终工作总结
2014/12/23 职场文书
基层组织建设年活动总结
2015/05/09 职场文书
2015年检察院个人工作总结
2015/05/20 职场文书
房屋产权证明书
2015/06/19 职场文书
python使用PySimpleGUI设置进度条及控件使用
2021/06/10 Python
MySQL Shell import_table数据导入的实现
2021/08/07 MySQL