Canvas неправильно рисует край при извлечении изображения из спрайта

1

Я попытался использовать ctx.drawImage (изображение, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); API для извлечения изображения из спрайта. Но я обнаружил, что Canvas делает край из смежных изображений, которые я не хочу.

Например:

Во-первых, я использую холст 800x400 для рисования 400x400 красных прямоугольников и рисую 400x200 зеленый прямоугольник после красного прямоугольника, а затем сохраняем данные в JPG файле.

Изображение 174551

Затем я хочу извлечь зеленый прямоугольник для рисования на другой холст, поэтому я использую синтаксис следующим образом:

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

В теории есть только данные о цвете от зеленого прямоугольника на холсте, но на левом краю есть красный цвет.

JSBIN SAMPLE LINK

Кто-нибудь знает причину возникновения этой проблемы? Не понимаю ли я API?

Заранее спасибо.

Теги:
canvas

1 ответ

3
Лучший ответ

Это связано с 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>
  • 0
    Спасибо за ваше подробное объяснение. Я ценю это!
  • 1
    Кстати, я только что проверил параметр качества по умолчанию toDataURL, я нашел статью, в которой сказано, что значение по умолчанию 0,92. stackoverflow.com/questions/33904144/...
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню