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

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

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

最近要做一个生成海报的h5, 原理就是用 canvas 的 drawImage 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 ,因此猜想把 canvas 的 css 大小设置为我们屏幕的大小,这样绘制应该就是这个屏幕的区域了。

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

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

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

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

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

2.2 绘制模糊

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

解决思路: 在浏览器的 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太大,绘制时间长,还可能会出错。二是浏览器上标题栏会占据高度,导致窗口大小比例是不对的,生成的图片会发生变形,需要注意处理一下,就不展开说了。


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

查看所有标签

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

Host Your Web Site In The Cloud

Host Your Web Site In The Cloud

Jeff Barr / SitePoint / 2010-9-28 / USD 39.95

Host Your Web Site On The Cloud is the OFFICIAL step-by-step guide to this revolutionary approach to hosting and managing your websites and applications, authored by Amazon's very own Jeffrey Barr. "H......一起来看看 《Host Your Web Site In The Cloud》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具