失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 解决canvas合成图片大小错误 模糊以及跨域的问题

解决canvas合成图片大小错误 模糊以及跨域的问题

时间:2020-11-03 13:37:03

相关推荐

解决canvas合成图片大小错误 模糊以及跨域的问题

最近要做一个生成海报的h5, 原理就是用canvasdrawImageAPI把图片画出来,想着应该很简单,却发现里面有大坑。在填完坑后分享下解决方案,文章主要围绕以下两个问题来展开。

绘制图片会有跨域的问题生成的图片、文字大小不正确,还会模糊,不清晰

1. demo初试

<style>.J_ret_poster {position: fixed;z-index: 999;top: 0;right: 0;bottom: 0;left: 0;}</style><canvas hidden id="J_poster">你的浏览器版本较低,请换个浏览器试试</canvas><script>const $ = q => document.querySelector(q),$JPoster = $('#J_poster'),$btn = $('J_btn'),ctx = $canvas.getContext('2d'),$bg = new Image(), // 需要的背景图片(海报底图)$retImg = new Image(), // 最终生成的图片winW = window.innerWidth,winH = window.innerHeight// 设置canvas的大小为全屏$JPoster.setAttribute('width', winW); $JPoster.setAttribute('height', winH);// 设置生成的图片相关信息$retImg.setAttribute('width', winW);$retImg.setAttribute('height', winH);$retImg.setAttribute('alt', '海报');$retImg.setAttribute('class', 'J_ret_poster');$bg.src = 'http://canvas-img.oss-cn-/normal.jpg';$bg.onload = () => {ctx.drawImage($bg, 0, 0, winW, winH); // 从窗口的左上角开始画起,铺满整个屏幕ctx.font = '14px Arial';ctx.fillStyle = '#fff';ctx.fillText('这是test测试文字123', 100, 100);const retUrl = $JPoster.toDataURL('image/png'); // 生成的图片url$retImg.setAttribute('src', retUrl);$retImg.onload = () => {$('body').appendChild($retImg); // 添加到body下}}</script>复制代码

运行之后出现错误

1.1 出现图片跨域问题

报了一个跨域的错误

1.2 为图片添加跨域请求头access-control-allow-origin:*

由于我这里使用的是阿里云的oss,这里就用图说明下该如何操作(没有阿里云oss的也可以自己用node进行转发)

然后又出现了问题!

这里是相关说明

1.3 为图片添加crossOrigin属性

$bg.crossOrigin = ''; // 跨域设置,这里不用设置为`Anonymous`也是可以的复制代码

然后图片就可以出来了

这时又出现了问题,图片尺寸不对

2. canvas大小错误以及模糊

2.1 大小错误

原因:需要绘制的图片尺寸(1242*2208)远大于我们的屏幕尺寸iphone 6sp414*736,因此猜想把canvascss大小设置为我们屏幕的大小,这样绘制应该就是整个屏幕的区域了。

// css定宽高为全屏$JPoster.style.width = winW + 'px';$JPoster.style.height = winH + 'px';复制代码

然后在chrome的模拟器下图片大小显示一切正常

但是,在手机上又出现了新的问题,图片和文字都是模糊的!!(看不出模糊的可以和后面的一张图对比看看)

2.2 绘制模糊

因为canvas不是矢量图,而是像图片一样是位图模式的。高dpi显示设备意味着每平方英寸有更多的像素。也就是说倍屏,浏览器就会以2个像素点的宽度来渲染一个像素,该canvasRetina屏幕下相当于占据了2倍的空间,相当于图片被放大了一倍,因此绘制出来的图片文字等会变模糊。 因此,要做Retina屏适配,关键是知道当前屏幕的设备像素比,然后将canvas放大到该设备像素比来绘制,然后将canvascss设置为屏幕的大小来展示。

解决思路: 在浏览器的window对象中有一个devicePixelRatio的属性,该属性表示了屏幕的设备像素比,即用几个像素点宽度来渲染1个像素。

类似的,在canvas context中也存在一个backingStorePixelRatio的属性,该属性的值决定了浏览器在渲染canvas之前会用几个像素来来存储画布信息。backingStorePixelRatio属性在各浏览器厂商的获取方式不一样,所以需要加上浏览器前缀来实现兼容。

这里是引用来源

代码实现:

let devRatio = window.devicePixelRatio || 1, // 获取设备像素比// ctx的像素比backingStore = ctx.backingStorePixelRatio ||ctx.webkitBackingStorePixelRatio ||ctx.mozBackingStorePixelRatio ||ctx.msBackingStorePixelRatio ||ctx.oBackingStorePixelRatio ||ctx.backingStorePixelRatio || 1;const ratio = devRatio / backingStore;// canvas放大像素比倍$JPoster.setAttribute('width', winW * ratio); $JPoster.setAttribute('height', winH * ratio);// canvas 放大后,相应的绘制图片也要放大ctx.scale(ratio, ratio);复制代码

然后我们的图片终于正常绘制出来了,手机上也显示清晰。

3. 其他需要注意的点

一是我们绘制的图片大小要控制好,太大就去压缩一下,不然生成的base64太大,绘制时间长,还可能会出错。二是浏览器上标题栏会占据高度,导致窗口大小比例是不对的,生成的图片会发生变形,需要注意处理一下,就不展开说了。

如果觉得《解决canvas合成图片大小错误 模糊以及跨域的问题》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。