最近做了一个海报生成的组件,需要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运行失败的问题解决 的文章就介绍到这了,更多相关canvas.todataurl在ios运行失败内容请搜索代码网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持代码网!
发表评论