我有一些 Canvas ,我希望在每个(现代)浏览器中都以像素完美的方式显示。默认情况下,具有高 DPI 屏幕的设备会缩放我的页面,以便所有内容看起来大小合适,但这会破坏*我的 Canvas 的外观。
如何确保 Canvas 中的一个像素 = 屏幕上的一个像素?最好这不会影响页面上的其他元素,因为我仍然想要例如为设备适当缩放的文本。
我已经尝试根据 window.devicePixelRatio
设置 Canvas 尺寸的样式。这使得 Canvas 大小合适,但内容看起来更糟。我猜这只是在它们已经错误地放大后缩小它们。
*如果你关心的话,因为 Canvas 使用抖动并且浏览器正在做某种 lerp 而不是最近邻
最佳答案
对我来说,只有结合不同的“像素完美”技术才能帮助存档结果:
获取 Canvas 并按像素比例缩放:
pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio
在调整大小时缩放 Canvas (避免 Canvas 默认拉伸(stretch)缩放)。
将 lineWidth 与 pixelRatio 相乘以找到合适的“真实”像素线宽:
context.lineWidth = thickness * pixelRatio;
注意:不确定它是否对所有设备都有效
检查线的粗细是奇数还是偶数。将 pixelRatio 的一半添加到奇数厚度值的线位置。
x = x + pixelRatio/2;
奇数行将被放置在像素的中间。上面一行是用来稍微移动一下的。
- 使用图像渲染:像素化;
function getPixelRatio(context) {
dpr = window.devicePixelRatio || 1,
bsr = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return dpr / bsr;
}
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
var pixelRatio = getPixelRatio(context);
var initialWidth = canvas.clientWidth * pixelRatio;
var initialHeight = canvas.clientHeight * pixelRatio;
window.addEventListener('resize', function(args) {
rescale();
redraw();
}, false);
function rescale() {
var width = initialWidth * pixelRatio;
var height = initialHeight * pixelRatio;
if (width != context.canvas.width)
context.canvas.width = width;
if (height != context.canvas.height)
context.canvas.height = height;
context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
}
function pixelPerfectLine(x1, y1, x2, y2) {
context.save();
context.beginPath();
thickness = 1;
// Multiple your stroke thickness by a pixel ratio!
context.lineWidth = thickness * pixelRatio;
context.strokeStyle = "Black";
context.moveTo(getSharpPixel(thickness, x1), getSharpPixel(thickness, y1));
context.lineTo(getSharpPixel(thickness, x2), getSharpPixel(thickness, y2));
context.stroke();
context.restore();
}
function pixelPerfectRectangle(x, y, w, h, thickness, useDash) {
context.save();
// Pixel perfect rectange:
context.beginPath();
// Multiple your stroke thickness by a pixel ratio!
context.lineWidth = thickness * pixelRatio;
context.strokeStyle = "Red";
if (useDash) {
context.setLineDash([4]);
}
// use sharp x,y and integer w,h!
context.strokeRect(
getSharpPixel(thickness, x),
getSharpPixel(thickness, y),
Math.floor(w),
Math.floor(h));
context.restore();
}
function redraw() {
context.clearRect(0, 0, canvas.width, canvas.height);
pixelPerfectLine(50,50,250,250);
pixelPerfectLine(120,0,120,250);
pixelPerfectLine(122,0,122,250);
pixelPerfectRectangle(10, 11, 200.3, 43.2, 1, false);
pixelPerfectRectangle(41, 42, 150.3, 43.2, 1, true);
pixelPerfectRectangle(102, 100, 150.3, 243.2, 2, true);
}
function getSharpPixel(thickness, pos) {
if (thickness % 2 == 0) {
return pos;
}
return pos + pixelRatio / 2;
}
rescale();
redraw();
canvas {
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-crisp-edges;
image-rendering: pixelated;
image-rendering: crisp-edges;
width: 100vh;
height: 100vh;
}
<canvas id="canvas"></canvas>
注意:截图中未触发调整大小事件,因此可能不准确。
关于html - 在所有设备上显示像素完美的 Canvas ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47696956/