Я попытался использовать ctx.drawImage (изображение, 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);
В теории есть только данные о цвете от зеленого прямоугольника на холсте, но на левом краю есть красный цвет.
Кто-нибудь знает причину возникновения этой проблемы? Не понимаю ли я API?
Заранее спасибо.
Это связано с jpeg-сжатием. Вероятно, вы установили параметр качества toDataURL('image/jpeg', quality)
на что-то большее, чем максимальное и по умолчанию 1
[edit: на самом деле, как выяснил 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>