【问题标题】:Canvas doesn't draw edge correctly when extract image from sprite image从精灵图像中提取图像时,画布无法正确绘制边缘
【发布时间】:2017-11-02 01:04:22
【问题描述】:

我尝试使用 ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); API 从精灵图像中提取图像。但是我发现 Canvas 会从我不想要的相邻图像中渲染边缘。

例如:

首先,我用一个800x400的画布画了400x400的红色矩形,红色矩形后画了400x200的绿色矩形,然后将数据保存为JPG文件。

然后我想提取绿色矩形绘制到另一个画布上,所以我使用这样的语法:

ctx.drawImage(this, 400, 0, 400, 400, 0, 0, 400, 400);

理论上,画布上只有绿色矩形的颜色数据,但左边有红色。

JSBIN SAMPLE LINK

有谁知道造成这个问题的原因吗?我是否误解了 API?

提前致谢。

【问题讨论】:

  • 不知道 api 有,但是你尝试在使用 drawImage 时从 1 开始而不是 0?

标签: javascript html canvas


【解决方案1】:

这是因为 jpeg 压缩。 您可能确实将 toDataURL('image/jpeg', quality) 的质量参数设置为最大 和默认 1 [编辑:实际上,正如 OP 发现的那样,默认值是 .92]
通过这样做,jpeg 算法将采用更大的像素块来进行有损压缩。您可以在图像上看到,在两个矩形确实发生碰撞的地方,存在一些抗锯齿伪影。

压缩率越低,这些伪影就越大:

// your original canvas
var canvas = document.createElement('canvas');
var _ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 400;
_ctx.fillStyle = 'white';
_ctx.fillRect(0, 0, 800, 400);
_ctx.fillStyle = 'red';
_ctx.fillRect(0, 0, 400, 400);
_ctx.fillStyle = 'green';
_ctx.fillRect(400, 100, 400, 200);


var img = document.createElement('img');
img.onload = function() {
  // lets zoom a little bit
  ctx.drawImage(this, 300, 0, 300, 300, 0, 0, 400, 400);
}
var ctx = document.getElementById('output').getContext('2d');

// since we do zoom the image, lets try to keep antialiasing as its minimum
ctx.webkitImageSmoothingEnabled =
  ctx.mozImageSmoothingEnabled =
  ctx.msImageSmoothingEnabled =
  ctx.imageSmoothingEnabled = false;

range.oninput = function() {
  img.src = canvas.toDataURL('image/jpeg', +this.value);
}
range.oninput();
<label>JPEG quality: <input type="range" id="range" min="0" max="1" step="0.01" value="1"></label><br>
<canvas id="output" height="400"></canvas>

JPEG 非常适合图片,但对于此类图像,您应该坚持使用 png,它可以提供无损压缩,甚至会在此精确图像上生成更小的图像尺寸:

var canvas = document.createElement('canvas');
var _ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 400;
_ctx.fillStyle = 'white';
_ctx.fillRect(0, 0, 800, 400);
_ctx.fillStyle = 'red';
_ctx.fillRect(0, 0, 400, 400);
_ctx.fillStyle = 'green';
_ctx.fillRect(400, 100, 400, 200);


var img = document.createElement('img');
img.onload = function() {
  // lets zoom even more
  ctx.drawImage(this, 300, 0, 200, 200, 0, 0, 400, 400);
}
var ctx = document.getElementById('output').getContext('2d');
ctx.webkitImageSmoothingEnabled =
  ctx.mozImageSmoothingEnabled =
  ctx.msImageSmoothingEnabled =
  ctx.imageSmoothingEnabled = false;
img.src = canvas.toDataURL('image/png');

canvas.toBlob(function(b){console.log('jpg_size', b.size)}, 'image/jpeg', .1);
canvas.toBlob(function(b){console.log('png_size', b.size)}, 'image/png');
&lt;canvas id="output" height="400"&gt;&lt;/canvas&gt;

【讨论】:

  • 感谢您的详细解释。我很感激!
  • 对了,我刚查了toDataURL的默认质量参数,发现有一篇文章说默认值为0.92。 stackoverflow.com/questions/33904144/…
  • @Sam,你完全正确,我忘记了,真丢脸...更新了。
猜你喜欢
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多