解决 canvas 绘图在高清屏中的模糊问题

为什么模糊

CSS 像素是一个抽象单位(1 px),浏览器根据某种规则将 css 像素转化为屏幕需要的实际像素值。

在高清屏之前,屏幕上显示一个像素点需要 1 x 1 个 css 像素。在高清屏,同样大小的屏幕上要显示一个点,就需要 n x 1 个 css 像素。这里的 n 就是设备像素比 devicePixelRatio >= 2.

也就是说,同样大小的区域,高清屏需要更多的 css 像素:css 像素不够,则会放大内容——变得模糊;css 像素足够,则会缩小内容——变得清晰。放大、缩小的比例由 devicePixelRatio 决定。

比如说 iPhone 4s,它的 devicePixelRatio 为 2,假设屏幕上有块区域大小为 100px x 100px,上面有张 100px x 100px大小的图片,那么这张图片会被放大 2 倍后再渲染到这块区域,所以看起来就模糊了。

canvas 绘图在高清屏中模糊

canvas 属于位图,绘制在它上面的文字、图片、线条也属于位图,经放大后就失真、显得模糊了。要解决这个问题,我们就需要 canvas 拥有更多的 css 像素,即让 canvas 足够大。多大才够呢?太大会不会浪费资源/性能?我们需要因地制宜,根据 devicePixelRatio 来决定画布的大小。

function setupCanvas(canvas) {
var dpr = window.devicePixelRatio || 1
var rect = canvas.getBoundingClientRect() canvas.width = rect.width * dpr
canvas.height = rect.height * dpr var ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr) return ctx
} // 现在我们只需要根据 UI 设计图绘制需要的内容
// 由于使用了 setupCanvas,绘制的内容在各种高清屏中表现清晰、一致
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();

在 setupCanvas 函数中,我们根据屏幕的 devicePixelRatio 对 canvas 画布本身进行放大,然后使用 ctx.scale() 放大 canvas 单位,这样在 ctx 上下文绘制的内容就会被放大,使得最后生成的图片清晰的显示在对应的屏幕上。

实际上,我们还要兼顾不同大小、不同分辨率的屏幕。一般设计师会给我们宽度为 375px 的设计图,这需要我们根据屏幕大小进行缩放:

function setupCanvas(canvas) {
const UI_WIDTH = 375
const DOC_WIDTH = document.documentElement.clientWidth
const DPR = window.devicePixelRatio || 1
let scale = (DPR * DOC_WIDTH / UI_WIDTH).toFIxed(2)
//let rect = canvas.getBoundingClientRect() canvas.width = canvas.width * scale
canvas.height = canvas.height * scale let ctx = canvas.getContext('2d')
ctx.scale(scale, scale) return ctx
}

术语

device pixel

设备像素(又称物理像素、屏幕像素)是显示屏的最小物理单元,是我们在屏幕上能看到的最小点。

device-independent pixel

设备无关像素(又称密度无关像素,DIP)是一个抽象单位,表示计算机中的一个虚拟点,由系统转为一个设备像素点。

devicePixelRatio

设备像素比,它的值等于设备像素/设备无关像素,devicePixelRatio = DP/DIP

css pixel

css 像素是浏览器使用的抽象单位,属于设备无关像素(DIP)。我们看到的内容,是浏览器将 css 像素转化为设备像素后的结果。

矢量图

矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真。

位图

位图图像(bitmap),亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。当放大位图时,图像就失真、模糊了。

引用

解决 canvas 绘图在高清屏中的模糊问题的更多相关文章

  1. 【转】解决 canvas 在高清屏中绘制模糊的问题

    来源: http://www.css88.com/archives/9297 使用 canvas 绘制图片或者是文字在 Retina 屏中会非常模糊.如图: 因为 canvas 不是矢量图,而是像图片 ...

  2. 【Canvas】311- 解决 canvas 在高清屏中绘制模糊的问题

    点击上方"前端自习课"关注,学习起来~ 一.问题分析 使用 canvas 绘制图片或者是文字在 Retina 屏中会非常模糊.如图: 因为 canvas 不是矢量图,而是像图片一样 ...

  3. 解决 canvas 在高清屏中绘制模糊的问题

    主要代码部分: <canvas id="my_canvas" width="540" heihgt="180"></can ...

  4. ArcGIS 在高清屏中主界面界面字体和图标显示过小,如何解决?

    作者:安日链接:https://www.zhihu.com/question/40658050/answer/132382971来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  5. 高清屏下canvas重置尺寸引发的问题

    我们知道,清空canvas画布内容有以下两个方法. 第一种方法是cearRect函数: context.cearRect(0,0,canvas.width,canvas.height) 第二种方法就是 ...

  6. Cocos2D瓦块地图高清屏(retina)显示比例问题的解决

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在Cocos2D的游戏编程里,常用到瓦块地图.而cocos2D ...

  7. 移动端,多屏幕尺寸高清屏retina屏适配的解决方案

    移动端高清.多屏适配方案 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页 ...

  8. Cocos2D iOS之旅:如何写一个敲地鼠游戏(一):高清屏显示和UIKit

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  9. 怎么在高清屏上画一条0.5px的边

    怎么在高清屏上画一条0.5px的边呢?0.5px相当于高清屏物理像素的1px.这样的目的是在高清屏上看起来会更细一点,效果会更好一点,例如更细的分隔线. 理论上px的最小单位是1,但是会有几个特例,高 ...

随机推荐

  1. mysql 字符串数值计算 精度丢失

    我进行了一些测试.truncate(abs('414')/100,2)truncate('414'/100,2)truncate('4.14',2)truncate('4.1400',2)都有精度丢失 ...

  2. mysql数据库进阶篇

    一.连表操作 1)为何需要连表操作 .把所有数据都存放于一张表的弊端 .表的组织结构复杂不清晰 .浪费空间 .扩展性极差 2)表设计,分析表与表之间的关系 寻找表与表之间的关系的套路 举例:emp表 ...

  3. 2018.10.24 NOIP模拟 小 C 的宿舍(分治)

    传送门 分治妙题. 没有这道题的暴力分今天又垫底了啊233 由于用了分治的方法,我们只用考虑左区间对右区间的贡献以及右区间对左区间的贡献. 可以发现如果从中点开始向两边递推最小值并用这个区间最小值来推 ...

  4. 【终极答案】搭建selenium3.11 +Firefox+python3.6自动化UI测试环境踩的坑

    1 运行之后,出现如下报错 Selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs ...

  5. jq页面加载分割截图

    <script> $(document).ready(function() { if (!Array.prototype.forEach) { Array.prototype.forEac ...

  6. IntelliJ IDEA使用心得之Maven项目篇

    今天和大家分享下,在IDEA中打开Maven项目的方法. 对于新版的IDEA可以直接打开Maven项目,但是对于旧版的IDEA需要使用Maven命令生成项目的IDEA配置文件. 在项目的根目录(即po ...

  7. redis.conf之save配置项解读

    配置示例: save 900 1 save 300 10 save 60 3600 配置解读: 1) “save 900 1”表示如果900秒内至少1个key发生变化(新增.修改和删除),则重写rdb ...

  8. Simultaneous Localization and Mapping Technology Based on Project Tango

    Abstract: Aiming at the problem of system error and noise in simultaneous localization and mapping ( ...

  9. Hdu 1009 FatMouse' Trade 2016-05-05 23:02 86人阅读 评论(0) 收藏

    FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...

  10. Scala_数据结构

    数据结构 容器(Collection) Scala提供了一套丰富的容器(collection)库,包括列表 (List).数组(Array).集合(Set).映射(Map)等 根据容器中元素的组织方式 ...