关于canvas在retina屏下绘制文字或图像模糊的解决方案

一、问题描述

最近在鼓捣canvas的时候,发现绘制在canvas上的文字(或图片)在retina屏幕上会出现显示模糊的问题,感觉很不爽,于是就Google了一番,还真发现了一个解决方案。有兴趣的同学可以去读一下原文,我在这里简单的记录一下。

先看一下Deom页面,对比一下前后两个效果,请务必在配有retina屏幕的设备上浏览(iOS6下的safari除外)。否则是看不到效果的。

二、问题分析

熟悉retina屏的同学应该都知道,在浏览器的window变量中有一个devicePixelRatio的属性,该属性决定了浏览器会用几个(通常是2个)像素点来渲染1个像素,举例来说,假设devicePixelRatio的值为2,一张100x100像素大小的图片,在retina屏幕下,会用2个像素点的宽度去渲染图片的1个像素点,因此该图片在retina屏幕上实际会占据200x200像素的空间,相当于图片被放大了一倍,因此图片会变得模糊。

知道了这一点,关于canvas的问题也就容易理解了。我们可以把canvas当成是一张图片,当浏览器去渲染canvas的时候,他会用2个像素点的宽度去渲染canvas,因此在大多数retina设备的浏览器中会出现绘制的图片或文字变模糊的情况。

请注意,我说的是大多数,难道还有例外?

没错,在iOS6下的safari会正常显示。

看来,我们需要再往深了刨。

在window中有一个devicePixelRatio的属性,类似的,在canvas context中也存在一个webkitBackingStorePixelRatio的属性(仅safari和chrome),该属性的值决定了浏览器在渲染canvas之前会用几个像素来来存储画布信息。在iOS6下的safari中的值是2,因此,如果将一张100x100像素的图片绘制到safari中,该图片首先会在内存中生成一张200x200的图片,然后浏览器渲染的时候,会按100x100的图片来渲染,因此就变成了200x200,正好和内存中的图片大小一致,因此在iOS的safari中不会出现失真的问题。但是在chrome和iOS7的safari中却出现了失真,其原因是,chrome和iOS7中的safari的webkitBackingStorePixelRatio值都是1。值得一提的是在iOS7中,苹果把webkitBackingStorePixelRatio的值置为了1,目的是处于性能的考虑,这一点在WWDC 2013中找到,感兴趣的同学可以异步What’s New in Safari and WebKit for Web Developers,搜索关键字‘backing’。

三、如何解决

扯了半天,还没有说怎么解决呢。其实方案很简单,也很容易明白。我们可以创建一个两倍于实际大小的canvas,然后用css样式把canvas限定在实际的大小。