html - 在所有设备上显示像素完美的 Canvas

标签 html html5-canvas

我有一些 Canvas ,我希望在每个(现代)浏览器中都以像素完美的方式显示。默认情况下,具有高 DPI 屏幕的设备会缩放我的页面,以便所有内容看起来大小合适,但这会破坏*我的 Canvas 的外观。

如何确保 Canvas 中的一个像素 = 屏幕上的一个像素?最好这不会影响页面上的其他元素,因为我仍然想要例如为设备适当缩放的文本。

我已经尝试根据 window.devicePixelRatio 设置 Canvas 尺寸的样式。这使得 Canvas 大小合适,但内容看起来更糟。我猜这只是在它们已经错误地放大后缩小它们。

*如果你关心的话,因为 Canvas 使用抖动并且浏览器正在做某种 lerp 而不是最近邻

最佳答案

对我来说,只有结合不同的“像素完美”技术才能帮助存档结果:

  1. 获取 Canvas 并按像素比例缩放:

    pixelRatio = window.devicePixelRatio/ctx.backingStorePixelRatio

  2. 在调整大小时缩放 Canvas (避免 Canvas 默认拉伸(stretch)缩放)。

  3. 将 lineWidth 与 pixelRatio 相乘以找到合适的“真实”像素线宽:

    context.lineWidth = thickness * pixelRatio;

注意:不确定它是否对所有设备都有效

  1. 检查线的粗细是奇数还是偶数。将 pixelRatio 的一半添加到奇数厚度值的线位置。

    x = x + pixelRatio/2;

奇数行将被放置在像素的中间。上面一行是用来稍微移动一下的。

  1. 使用图像渲染:像素化;

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/

相关文章:

jquery - 从一个 XML XSLT 到 HTML 制作两列

jquery - 使用 jquery 动态更改移动内容 slider 宽度以进行纵向和横向

javascript - jQuery 在具有相同类的多个 div 上切换

html - 如何从 HTML 文档中删除表格?

javascript - 在 Canvas 上绘制之前向图像添加滤镜

HTML5 颜色输入事件在颜色选择器中鼠标弹起时触发

分层 Canvas 与手动drawImage()的性能

javascript - 重新排列预先存在的物理形态字段

javascript - Internet Explorer 9 中的 HTML5 Image.onload 竞争条件

javascript - 如果 Canvas 同源标志脏了,如何将图像保存到相册