Canvas绘图的时候为什么会模糊,该怎么解决?

我们在进行canvas开发的时候,需要绘制一些文字和图片,绘制之后发现是模糊的,先不说怎么解决,这个原因是什么呢?首先我们要从Retina技术说起:所谓“Retina”是一种显示技术,可以将把更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度,由摩托罗拉公司研发。而现在手机端大屏很多都用了该技术,甚至Macbook上也支持该技术。

用Canvas绘图的时候为什么会模糊,该怎么解决?

在JS中的有一个变量:window.devicePixelRatio(设备像素比),是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。如果等于2,那就是物理上2个像素点来显示1个独立像素,这样以来再屏幕物理尺寸不变的情况下,屏幕的物理像素点越多,理论上支持的分辨率越高,而且更加细腻。

那为什么用canvas绘制就模糊了呢?

因为canvas的context对象也有一个:webkitBackingStorePixelRatio,该属性的值决定了浏览器在渲染canvas之前会用几个像素来存储画布信息,canvas相当于一个图片,而且在chrome确实可以右键菜单直接存储为图片的。
如果webkitBackingStorePixelRatio的值为1,此时你用canvas画了一个300*300的区域,那这个区域物理像素也是300*300,等于没有发挥出Retina技术的优势。

知道了原因,那么我们在渲染canvas的时候,想办法让canvas用的物理像素点跟window.devicePixelRatio匹配即可。当webkitBackingStorePixelRatio=1的时候,canvas的width和height代表具体物理像素点,但是通过css设置的width和height则代表我们人眼看到的像素尺寸。在Retina显示屏里,如果devicePixelRatio=2的话,我们通过css设置200px,实际上内存中会使用400个像素点来渲染,但看到的还是200px,只是更清晰了。

解决办法,无非就是获取上面提到的变量,然后做判断,来重置canvas宽高做缩放。

贴一段示例 /** * Writes an image into a canvas taking into * account the backing store pixel ratio and * the device pixel ratio. * * @author Paul Lewis * @param {Object} opts The params for drawing an image to the canvas */ function drawImage(opts) { if(!opts.canvas) { throw("A canvas is required"); } if(!opts.image) { throw("Image is required"); } // get the canvas and context var canvas = opts.canvas, context = canvas.getContext('2d'), image = opts.image, // now default all the dimension info srcx = opts.srcx || 0, srcy = opts.srcy || 0, srcw = opts.srcw || image.naturalWidth, srch = opts.srch || image.naturalHeight, desx = opts.desx || srcx, desy = opts.desy || srcy, desw = opts.desw || srcw, desh = opts.desh || srch, auto = opts.auto, // finally query the various pixel ratios devicePixelRatio = window.devicePixelRatio || 1, backingStoreRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1, ratio = devicePixelRatio / backingStoreRatio; // ensure we have a value set for auto. // If auto is set to false then we // will simply not upscale the canvas // and the default behaviour will be maintained if (typeof auto === 'undefined') { auto = true; } // upscale the canvas if the two ratios don't match if (auto && devicePixelRatio !== backingStoreRatio) { var oldWidth = canvas.width; var oldHeight = canvas.height; canvas.width = oldWidth * ratio; canvas.height = oldHeight * ratio; canvas.style.width = oldWidth + 'px'; canvas.style.height = oldHeight + 'px'; // now scale the context to counter // the fact that we've manually scaled // our canvas element context.scale(ratio, ratio); } context.drawImage(pic, srcx, srcy, srcw, srch, desx, desy, desw, desh); }

相关阅读