我尝试使用 ctx.drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight); API从精灵图像中提取图像。但我发现Canvas渲染了我不想要的相邻图像的边缘。
例如:
首先,我使用800x400画布绘制400x400红色rect,并在红色rect后绘制400x200绿色rect,然后将数据保存到JPG文件。
然后我想提取绿色矩形以绘制到另一个画布上,所以我使用这样的语法:
ctx.drawImage(this, 400, 0, 400, 400, 0, 0, 400, 400);
理论上,画布上只有绿色矩形的颜色数据,但左边有红色。
有谁知道造成这个问题的原因?我是否误解了API?
提前致谢。
答案 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>