从精灵图像中提取图像时,画布无法正确绘制边缘

时间:2017-06-01 03:37:21

标签: javascript html5 canvas

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

例如:

首先,我使用800x400画布绘制400x400红色rect,并在红色rect后绘制400x200绿色rect,然后将数据保存到JPG文件。

enter image description here

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

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

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

JSBIN SAMPLE LINK

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

提前致谢。

1 个答案:

答案 0 :(得分:3)

这是因为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');
<canvas id="output" height="400"></canvas>