HTML canvas 线条颜色不准确

HTML canvas line color is not accurate

有人可以解释一下为什么 canvas 不遵循颜色选择以及如何解决它以便绘制“真实”颜色吗? 我知道 canvas 使用 0.5 像素坐标,所以我尝试使用 0.5 增量绘制,但它仍然使用时髦的颜色绘制(使用 ColorCop 放大并检查每个像素的颜色:

这是一个小片段,应该画蓝线,两条线彼此相邻,第三条线相距 1 个像素,结果只有第一条线是真蓝色,其他所有线都是紫色或更糟,包括 first/last 第一行像素:

const canvas = document.getElementById("line"),
      ctx = canvas.getContext("2d");

canvas.width = canvas.height = 100;
ctx.strokeStyle = 'blue';
ctx.lineCap = "square";
ctx.imageSmoothingEnabled = false;

ctx.moveTo(10.5, 40.5);
ctx.lineTo(80.5, 40.5);

ctx.moveTo(10.5, 41.5);
ctx.lineTo(80.5, 41.5);

ctx.moveTo(10.5, 43.5);
ctx.lineTo(80.5, 43.5);

ctx.stroke();
<canvas id="line"></canvas>

我的显示器分辨率为 2560x1440,缩放比例为 100%。不使用 system/browser/software 或任何类型的 zoom/scale。 如果我在 MS Paint 中绘制一个像素,我会在显示器上看到一个像素没有抗锯齿,没有伪影。

这样做,您的 canvas 将显示高分辨率像素

  1. 将canvas宽度和高度设置为(所需的宽度和高度)* devicePixelRatio * 2

  2. 使用 css 样式 属性 将其重新指定为您想要的宽度和高度

  3. 缩放上下文 2、2

    默认情况下,canvas 上的一个单位正好是一个像素。缩放 转换修改此行为。例如,比例因子 0.5 导致单位大小为 0.5 像素;因此,形状以正常尺寸的一半绘制。类似地,比例因子 2.0 会增加单位大小,使一个单位变成两个像素;因此绘制的形状是正常尺寸的两倍。

const width = height = 100
const pixelRatio = window.devicePixelRatio * 2;
const canvas = document.getElementById('line');
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
const ctx = canvas.getContext("2d");
ctx.scale(pixelRatio, pixelRatio);

ctx.strokeStyle = 'blue';
ctx.lineCap = "square";

ctx.moveTo(10.5, 40.5);
ctx.lineTo(80.5, 40.5);

ctx.moveTo(10.5, 41.5);
ctx.lineTo(80.5, 41.5);

ctx.moveTo(10.5, 43.5);
ctx.lineTo(80.5, 43.5);

ctx.stroke();
<canvas id="line"></canvas>

您可能使用的是高分辨率显示器。 CSS 将缩放您的 canvas 并创建抗锯齿。

为了克服这个问题,您可以将 canvas 的大小乘以显示器的像素比,然后使用 CSS:

缩小到预期大小

const canvas = document.getElementById("line"),
      ctx = canvas.getContext("2d"),
      dPR = window.devicePixelRatio;

// multiply by dPR
canvas.width = canvas.height = 100 * dPR;
// downscale through CSS
canvas.style.width = canvas.style.height = "100px";
ctx.scale(dPR, dPR);

ctx.strokeStyle = 'blue';
ctx.lineCap = "square";
ctx.imageSmoothingEnabled = false;

ctx.moveTo(10.5, 40.5);
ctx.lineTo(80.5, 40.5);

ctx.moveTo(10.5, 41.5);
ctx.lineTo(80.5, 41.5);

ctx.moveTo(10.5, 43.5);
ctx.lineTo(80.5, 43.5);

ctx.stroke();
<canvas id="line"></canvas>