• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

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

    发布者: 天下网吧 | 发布时间: 2025-6-16 12:32| 查看数: 116| 评论数: 0|帖子模式

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

    上面加载了两张本地图片,两张异地图片,写了一些文字;在windows谷歌浏览器跑是好的,是吧,图片画出来,感觉无压力;用安卓也是好的,很开心;可是到IOS手机上,我去,怎么图片显示不出来啊,然后
    try catch 错误,没啥有用的信息;
    1. try {
    2. // 将canvas对象转化为image/png
    3.    var dataUrl = canvas.toDataURL('image/png')
    4. } catch (err) {
    5.    console.log(err)
    6. }
    复制代码
    我擦,这怎么办???
    然后去cnbing搜,好多相同问题,好多原因,有个老外说动态更改canvas宽高无法再ios画出图片;还有的人说:
    图片文件 size 太大,是否图片超过了 3M ? -----------
    1. 我看了下生成的图片才几百kb PASS
    复制代码
    图片的 dimension 太大,是否图片尺寸超过了 1000 x 1000 像素?
    1. 我的尺寸确实超过了,宽高都超了,然而测试了下小的宽高,照旧ios画不出来啊~~~PASS
    复制代码
    你指定的 mime_type 不支持,你用的是哪个 mime type?—
    1. canvas的 toDataURL API我看过了,可以支持三个类型,各试了一遍,无果 PASS
    复制代码
    先上我的代码:
    1. <template>
    2.     <div id="Poster">
    3.         <div class="mask" @click="hidePoster()"></div>
    4.         <canvas ref="canvas" width="588" height="1044" style="display:none;"></canvas>
    5.         <div ref="box" id="Poster-box" @click.stop>
    6.           <span class="close"  @click="hidePoster()"></span>
    7.         </div>
    8.         <p class="tip">长安按海报发送给朋友</p>
    9.     </div>
    10. </template>
    复制代码
    1. <script>
    2. export default {
    3.   data () { // 参数
    4.     const u = navigator.userAgent // ios终端
    5.     const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios终端
    6.     return { // 返回参数
    7.       localUrl: isIOS ? location.href.split('#')[0] : location.href, // 当前路径
    8.       canvas: Object // canvas对象
    9.     }
    10.   },
    11.   mounted () {
    12.     this.initCanvas()
    13.   },
    14.   methods: {
    15.     /**
    16.      * 隐藏海报
    17.      */
    18.     hidePoster () {
    19.       this.$emit('hide')
    20.     },
    21.     /**
    22.      * 加载图片
    23.      * @param {Object} img 图片地址
    24.      * @return {Promise} img dom
    25.      */
    26.     loadImage (img) {
    27.       return new Promise((resolve, reject) => {
    28.         // image dom 对象
    29.         const $image = document.createElement('img')
    30.         if (img.isCross_domain) {
    31.           console.log(img.url)
    32.           $image.setAttribute('crossOrigin', 'Anonymous')
    33.         }
    34.         $image.onload = () => {
    35.           resolve($image)
    36.         }
    37.          $image.src = img.url
    38.         $image.onerror = reject
    39.       })
    40.     },
    41.     /**
    42.      * init初始化canvas函数
    43.      */
    44.     async initCanvas () {
    45.       // 获取vue实例
    46.       var vm = this
    47.       vm.$indicator.open({
    48.         text: '加载中...',
    49.         spinnerType: 'fading-circle'
    50.       })
    51.       this.canvas = this.$refs.canvas.getContext('2d')
    52.       this.canvas.height = 400
    53.       this.canvas.width = 300
    54.       this.canvas.fillStyle = '#ffffff'
    55.       this.canvas.fillRect(0, 0, 588, 1044)

    56.       // image urls
    57.       const imgArr = [
    58.         {
    59.           url: require('../assets/poster-banner.png'),
    60.           isCross_domain: false
    61.         },
    62.         {
    63.           url: require('../assets/shadow.png'),
    64.           isCross_domain: false
    65.         },
    66.         {
    67.           url: 'https://s3-011-shinho-syj-uat-bjs.s3.cn-north-1.amazonaws.com.cn/mall/2019_06/border04.png',
    68.           isCross_domain: true
    69.         },
    70.         {
    71.           url: 'https://s3-011-shinho-syj-uat-bjs.s3.cn-north-1.amazonaws.com.cn/mall/2019_06/132.jpg',
    72.           isCross_domain: true
    73.         }
    74.       ]
    75.       // image doms
    76.       await Promise.all(imgArr.map(img => this.loadImage(img))).then((imgs) => {
    77.         console.log('done')
    78.         this.canvas.drawImage(imgs[0], 0, 0, 588, 216 * 2)
    79.         this.canvas.drawImage(imgs[1], 97 * 2, 166 * 2, 100 * 2, 100 * 2)

    80.         this.canvas.save()
    81.         this.canvas.beginPath()
    82.         this.canvas.arc(147 * 2, 214 * 2, 34 * 2, 0, 2 * Math.PI, false)
    83.         this.canvas.clip()
    84.         this.canvas.drawImage(imgs[2], 113 * 2, 180 * 2, 68 * 2, 68 * 2)
    85.         this.canvas.restore()
    86.         this.canvas.drawImage(imgs[3], 189 * 2, 409 * 2, 88 * 2, 88 * 2)
    87.         // 绘制文字
    88.         this.drawText('我就是个我就账号账号', 147 * 2, 278 * 2, 290 * 2, '#333333', '32px PingFangSC-Regular ')
    89.         this.drawText('荣誉称号是我', 147 * 2, 300 * 2, 290 * 2, '#999999', '26px PingFangSC-Regular ')
    90.         this.drawText('距离冲榜还差10人', 147 * 2, 340 * 2, 290 * 2, '#FA6F5B', 'bold 36px arial')
    91.         this.drawText('快来助我冲榜赢红烧酱油吧', 147 * 2, 370 * 2, 290 * 2, '#FA6F5B', 'bold 36px arial ')
    92.         this.drawText('扫描二维码', 180 * 2, 443 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
    93.         this.drawText('直达冲榜活动', 180 * 2, 463 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
    94.         this.drawText('邀请好友跟你一起冲大奖', 180 * 2, 483 * 2, 172 * 2, '#333333', '28px PingFangSC-Regular ', 'right')
    95.         this.showPic()
    96.         vm.$indicator.close()
    97.       })
    98.     },
    99.     /**
    100.      * 绘制文字
    101.      * @param {String} title  文字名称
    102.      * @param {Number} x  x轴坐标
    103.      * @param {Number} y  y轴坐标
    104.      * @param {Number} maxwidth  最大宽度
    105.      * @param {String} color  颜色
    106.      * @param {String} font  字体样式
    107.      * @param {String} textalign  文字排版
    108.      */
    109.     drawText (title, x, y, maxwidth, color, font, textalign = 'center') {
    110.       this.canvas.font = font
    111.       this.canvas.textAlign = textalign
    112.       this.canvas.fillStyle = color
    113.       this.canvas.fillText(title, x, y, maxwidth)
    114.     },
    115.     /**
    116.      * 显示图片
    117.      */
    118.     showPic () {
    119.       // 获取canvas对象
    120.       let canvas = this.$refs.canvas

    121.       try {
    122.         // 将canvas对象转化为image/png
    123.         var dataUrl = canvas.toDataURL('image/png')
    124.       } catch (err) {
    125.         console.log(err)
    126.       }

    127.       // 创建img 元素
    128.       var newImg = document.createElement('img')
    129.       newImg.src = dataUrl
    130.       newImg.style.width = '100%'
    131.       newImg.style.height = '100%'
    132.       newImg.className = 'img-poster'
    133.       newImg.style.borderRadius = '8px'
    134.       this.$refs.box.appendChild(newImg)
    135.     }

    136.   }
    137. }
    138. </script>
    复制代码
    盘查了好久,最后找到bug,就是下面这个function
    1. /**
    2.      * 加载图片
    3.      * @param {Object} img 图片地址
    4.      * @return {Promise} img dom
    5.      */
    6.     loadImage (img) {
    7.       return new Promise((resolve, reject) => {
    8.         // image dom 对象
    9.         const $image = document.createElement('img')
    10.         $image.src = img.url
    11.         if (img.isCross_domain) {
    12.           console.log(img.url)
    13.           $image.setAttribute('crossOrigin', 'Anonymous')
    14.         }
    15.         $image.onload = () => {
    16.           resolve($image)
    17.         }
    18.         $image.onerror = reject
    19.       })
    20.     },
    复制代码
    有没有注意到crossOrigin属性是在src属性之后赋值的;/(ㄒoㄒ)/~~
    1. crossOrigin属性必须在src属性之前赋值
    复制代码
    1. crossOrigin属性必须在src属性之前赋值
    复制代码
    1. crossOrigin属性必须在src属性之前赋值
    复制代码
    尽管没有找到准确的文档明确指定crossOrigin属性必须在src属性之前赋值,但是要适配IOS确实要这么做;
    大家如果对 crossorigin 有疑问可以看一下MDN对crossorigin的解释:
    https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image
    里面讲了画布的污染和解决方法,就是设置 crossorigin = “Anonymous”;里面的方法也是先设置crossorigin在图片加载完后设置 src;
    如下
    1. var img = new Image,
    2.     canvas = document.createElement("canvas"),
    3.     ctx = canvas.getContext("2d"),
    4.     src = "http://example.com/image"; // insert image url here

    5. img.crossOrigin = "Anonymous";

    6. img.onload = function() {
    7.     canvas.width = img.width;
    8.     canvas.height = img.height;
    9.     ctx.drawImage( img, 0, 0 );
    10.     localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
    11. }
    12. img.src = src;
    13. // make sure the load event fires for cached images too
    14. if ( img.complete || img.complete === undefined ) {
    15.     img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    16.     img.src = src;
    17. }
    复制代码
    到此这篇关于关于canvas.toDataURL 在iOS运行失败的问题解决 的文章就介绍到这了,更多相关canvas.toDataURL在iOS运行失败内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

    来源:https://www.jb51.net/html5/745320.html
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×

    最新评论

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表