canvas生成海报大小错误、模糊以及跨域的问题

栏目: Html5 · 发布时间: 5年前

内容简介:最近要做一个生成海报的h5, 原理就是用运行之后出现错误报了一个跨域的错误

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

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

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>
 <button class="J_btn">生成海报</button>
 
 <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-shenzhen.aliyuncs.com/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 出现图片跨域问题

canvas生成海报大小错误、模糊以及跨域的问题

报了一个跨域的错误

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

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

canvas生成海报大小错误、模糊以及跨域的问题

然后又出现了问题!

canvas生成海报大小错误、模糊以及跨域的问题
这里是相关说明

1.3 为图片添加crossOrigin属性

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

然后图片就可以出来了

canvas生成海报大小错误、模糊以及跨域的问题

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

2. canvas大小错误以及模糊

2.1 大小错误

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

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

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

canvas生成海报大小错误、模糊以及跨域的问题

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

canvas生成海报大小错误、模糊以及跨域的问题

2.2 绘制模糊

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

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

举例来说,假设 devicePixelRatio 的值为 2 ,一张 100×100 像素大小的图片,在 Retina 屏幕下,会用 2 个像素点的宽度去渲染图片的 1 个像素点,因此该图片在 Retina 屏幕上实际会占据 200×200 像素的空间,相当于图片被放大了 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);
复制代码

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

canvas生成海报大小错误、模糊以及跨域的问题

3. 其他需要注意的点

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CSS实战手册

CSS实战手册

David Sawyer McFarland / 俞黎敏 / 电子工业出版社 / 2007-07-01 / 68.00元

CSS是一场革命 借用quirksMode的PPK(Peter-Paul Koch)的话来说:CSS是一场革命。 Ajax的浪潮正在逐步改变着Web开发的方式。谈到Ajax,开发人员似乎更注重于 XMLHttpRequest 和 JavaScript ,而淡忘了Ajax还有一个重要的组成部分 CSS。 事实上,CSS和DOM、xHTML以及粘合它们的JavaScript密不可分,......一起来看看 《CSS实战手册》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具