如何设置HTML5画布大小以匹配设备像素的显示尺寸

6

在HTML5画布中,是否可以设置位图的大小,使其与设备像素的显示大小完全匹配,即在window.devicePixelRatio不是整数时,使用的物理像素数量来显示画布?

webglfundamentals上有一个很好的描述如何调整画布大小的说明,但它不能正确处理非整数的devicePixelRatio。 我的理解:

  • 使用CSS设置画布的显示大小,例如:canvas {width: 200px;}
  • 使用HTML中的<canvas width="100"/>或JS中的canvas.width = 100设置底层位图大小。
  • 位图将被拉伸以适应CSS大小(受object-fitobject-position影响)。
  • 我们可以将位图大小设置为涉及canvas.clientWidth的某个表达式。
  • canvas.clientWidth是一个整数,其单位是CSS像素,是内容的计算宽度(加上填充)。 我不知道浏览器实际上是否将内容绘制到整数个CSS像素或整数个设备像素中。

因此,webglfundamentals建议使用类似以下代码:

canvas.width = Math.floor(canvas.clientWidth * window.devicePixelRatio);

但是如果window.devicePixelRatio是一个分数,有时候这种方法行不通(在整数坐标上绘制的2像素宽的线条会变得模糊)。我的1920x1080屏幕默认设备像素比例为1.5,页面缩放可能会影响到此值,所以导致设备像素比例往往不是一个整数。我们该怎么办呢?


根据MDN,“window.devicePixelRatio”永远不会是一个整数,而是一个双精度浮点值。 - Jack Bashford
@JackBashford 我认为他指的是自然数而不是分数。 - NielsNet
他的意思是他想四舍五入吗,@NielsNet? - Jack Bashford
你能不能只是使用CSS将画布的宽度和高度设置为100%呢? - Jonathan
以下链接对我很有帮助:https://dev59.com/jHfZa4cB1Zd3GeqPSoaW#35244519 - Simon
显示剩余2条评论
2个回答

3

我知道这是一个旧的帖子,但我希望我能为其他来到这里的人提供一些帮助。

在我的经验中,即使使用非整数的devicePixelRatio值,也有一种方法可以使“画布像素”尽可能接近1:1的比例与“设备像素”匹配,这是基于Canvas WebGL的游戏引擎。

首先,我们需要了解三件事:

  • CSS大小:指CSS像素(px)单位下Canvas DOM元素的实际大小。

  • 画布大小:通过设置元素属性(例如canvasElem.width = 100;)来设置画布的逻辑大小,这会影响您的渲染空间。

  • 设备像素比:从window获取的值,有效地描述了物理像素CSS像素之间的比率。

简要示例

假设您的devicePixelRatio2.625,并且您的移动设备报告了一个411 x 487的屏幕/窗口大小-一个奇怪的大小-您可能会说,但这是以CSS像素单位表示的,如果我们将它们乘以devicePixelRatio,我们得到一个大小为1078 x 1278的尺寸,这告诉我们,最可能的是设备屏幕实际上是一个1080 x 1280的屏幕,正如您最喜欢的手机制造商所宣传的那样。
现在,来调整大小...
假设我们想要一个填满整个屏幕的画布。将您的CSS尺寸设置为屏幕大小(或任何您想要的框大小)。
canvas.style.width = '411px';
canvas.style.height = '487px';

现在将画布大小设置为相同,但按devicePixelRatio缩放:

canvas.width = 411 * window.devicePixelRatio;
canvas.height = 487 * window.devicePixelRatio;

现在你可以渲染你的图像了。

当浏览器计算布局时,它将需要缩小你的画布以适应其 DOM 矩形区域,缩小比例是 cssSize / canvasSize,得到一个缩小比例为 1 / devicePixelRatio

然后当浏览器需要将布局渲染到物理屏幕上时,它会通过 devicePixelRatio 缩放,从而留下总缩放比例为 1.0

简而言之

超采样。通过将画布的逻辑大小放大 devicePixelRatio 倍,同时保持 CSS 大小为所需大小,让浏览器处理剩余部分。

注意: 如果你的渲染期望画布具有特定大小,并且这种 "放大" 混乱了你的布局和/或计算,请使用 canvas 的 setTransform 方法将你的 "逻辑单位" 缩小 1.0 / devicePixelRatio,完全不会损失任何质量。


0

1px是CSS/DOM领域中的逻辑长度单位。点。

因此,我认为您不会找到可靠的方法来获取物理像素。请查看this

这就是为什么在Sciter中,我将px单位表示为设备的物理像素。并引入了dip单位,它们是逻辑像素-由设备表面上的标尺测量的1/96英寸(因此1dip〜W3C CSS的1px)。

我根本不明白如何在没有定义设备像素对象的能力的情况下进行严肃的UI开发。


感谢您作为UI专家的回复,以及提供链接到这个广受关注的问题。我仍然会保持问题的开放一段时间。 - user2357
正是苹果公司在他们的无限智慧下,为了推销他们的第一款iPhone,提出了一个相当愚蠢的额外“间接层”或复杂性,现在被称为“逻辑像素”。自那以后,我们一直在抓狂。 - Armen Michaeli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接