Canvas 在高清屏下绘制图片变模糊的解决方法

以前我在 SF 上回答过「html5 canvas绘制图片模糊的问题」,可是多是因为我给出的答案过于简略,加上答案中的 demo 连接已经失效,不少人反映这种办法并很差使。可是我在给出答案以前是在小米2 和 iPhone 上测试过的,没有任何问题。下面我会一步一步地描述具体的步骤。html

前提条件

假设咱们要在 canvas 中绘制一张 300 x 90 的图片,而且要保证它在高清屏中不模糊。那么咱们首先要准备一张 600 x 180 的图片,处理太高清屏的同窗应该会有这方面的经验。html5

问题重现

OK,咱们先把问题重现一下,以便有一个更直观的了解。下面是相关的代码(为了简单起见,我把代码都写在了 HTML 文档里面):git

<!-- 经过 img 标签引入图片,以便绘制到 canvas 中 -->
<img src="html5rocks.png" alt="" width="300" height="90">

<!-- canvas -->
<canvas width="300" height="90"></canvas>

<script>
    function init() {
        var canvas = document.querySelector('canvas');
        var ctx = canvas.getContext('2d');
        ctx.drawImage(document.querySelector('img'), 0, 0, 300, 90);
    }
    window.onload = init;
</script>

代码很简单,没有作任何处理,具体的效果和完整的代码能够查看这个 DEMO,这个 demo 在高清屏的手机中会出现的问题:canvas 中的图片变模糊了!。github

至于为何会变模糊,这和浏览器处理 canvas 的方式有关,相关的文章能够参考这篇 High DPI Canvas,这里不做深刻介绍。web

解决问题

首先,引入 hidpi-canvas-polyfill

其实,不仅是绘制图片时会出现模糊的问题,正常状况下,在高清屏的设备中,任何绘制在 canvas 中的图形(包括文字)都会出现模糊的问题。上面这个 polyfill 就是为了解决这个问题,可是它没有处理图片。canvas

接下来,修改绘制图片的代码

init 函数修改为下面这样:segmentfault

function init() {
    var canvas = document.querySelector('canvas');
    var ctx = canvas.getContext('2d');

    // polyfill 提供了这个方法用来获取设备的 pixel ratio
    var getPixelRatio = function(context) {
        var backingStore = context.backingStorePixelRatio ||
            context.webkitBackingStorePixelRatio ||
            context.mozBackingStorePixelRatio ||
            context.msBackingStorePixelRatio ||
            context.oBackingStorePixelRatio ||
            context.backingStorePixelRatio || 1;
    
        return (window.devicePixelRatio || 1) / backingStore;
    };

    var ratio = getPixelRatio(ctx);
    
    // 注意,这里的 width 和 height 变成了 width * ratio 和 height * ratio
    ctx.drawImage(document.querySelector('img'), 0, 0, 300 * ratio, 90 * ratio);
}

能够点击这里查看完整的代码和效果,在高清屏的设备中打开,看看 cavans 中的图片是否完美显示。浏览器

说明

这个解决方案本质上和 @白一梓 的答案是同样的:先放大 canvas,再用 CSS 将其限制回原始大小。app

若是你看了 polyfill 的代码就会明白其中的原理了,这个 polyfill 的代码十分简短明了,它作了两件事:一是将 canvas 的高和宽分别乘以 ratio 将其放大,而后又用 CSS 将高和宽限制成初始的大小;二是 hack canvas 中经常使用的函数,如:fillRect, clearRect, lineTo, arc 等,将它们的参数都乘以 ratio,以方便咱们能够像之前那样使用这些方法,而不用在传参的时候手动乘以 ratio。函数

相关文章
相关标签/搜索