HTML5 - Плохое качество изображения при изменении размера холста

Я занимаюсь созданием и загрузкой изображений с изменением размера изображения на стороне клиента (с использованием холста HTML5). Все работает, но проблема в том, что качество изображения не очень хорошее.

Вот ссылка на фотогалерею (в процессе работы) с изображениями, которые сгенерировал мой код изменения размера/загрузки.

Вы видите, что я имею в виду под низким качеством? Множество зубчатых краев, особенно на миниатюрных изображениях. Любые идеи о том, как это исправить?

Вот мой javascript для создания эскизов:

img.onload = function()
{
   var canvasWidth = 150;
   var canvasHeight = 150;
   var Rz = resizeCanvasSmall(img,canvasID,canvasWidth,canvasHeight);

   ctx.drawImage(img,Rz[0],Rz[1],Rz[2],Rz[3],Rz[4],Rz[5],Rz[6],Rz[7]);
   dataurl = canvas.toDataURL("image/jpeg",0.8);  // File type and quality (0.0->1.0)
   UploadFile();
}


// Function to resize canvas (for thumbnail images)
// img = image object, canvas = canvas element ID
function resizeCanvasSmall(img,canvas,width,height)
{
var sx; //The x coordinate where to start clipping
var sy; //The y coordinate where to start clipping
var swidth; //The width of the clipped image
var sheight; //The height of the clipped image

var aspectRatio = width / height;

if (img.width > img.height) // If landscape
{
    sheight = img.height;
    swidth = img.height * aspectRatio;
    sy = 0;
    sx = (img.width - swidth) / 2;
}
else //If portrait
{
    swidth = img.width;
    sheight = img.width / aspectRatio;
    sx = 0;
    sy = (img.height - sheight) / 2;
}

document.getElementById(canvas).width = width;
document.getElementById(canvas).height = height;

return [sx,sy,swidth,sheight,0,0,width,height];
}

Ответ 1

Общее правило для изменения размера больших сумм - это прыгать с мощностями по два, чтобы у вас было меньше артефактов сглаживания, а затем просто сделайте один окончательный размер для остальной части пути. Пример: если вам нужно перемасштабировать 1000px до 68px, это уменьшит до 500px, затем 250px, затем 125px, затем до 68px. Он всегда имеет силу от двух до последнего.

Кроме того, вы должны сохранить соотношение сторон, или вы получите фальшивое сглаживание по диагонали. Если вам нужны квадратные миниатюры из изображений, отличных от квадратов, то размер вниз как можно ближе к вашему целевому квадрату, при этом все еще больше, а затем обрезайте его по центру. (Или идите поменьше и положите его). Вы должны сохранить соотношение сторон любой ценой.

Чтобы получить еще лучшие результаты, чем то, что я описал, вам придется реализовать свои собственные алгоритмы изменения размера, которые будут намного медленнее (поскольку они будут в JS вместо оптимизированного собственного кода). В качестве альтернативы может быть и переход в WebGL.

Ответ 2

http://output.jsbin.com/palota/1/

Я сделал плагин изменения размера холста. Один из файлов может быть включен в интерфейс. Он имеет пиксель за пикселем. Вместо того, чтобы захватывать соседний пиксель, он усредняет цвета, поэтому средний цвет пикселей одинаковый от исходного к новому.

https://github.com/danschumann/limby-resize

и фактический файл для включения -

https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

Это приведет к тому же типу изменения размера, что и фотошоп или imagemagick.

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

Математика за алгоритмом

позволяет сказать, что мы имеем 3 пикселя, которые изменяются в 2 пикселя.

обычно каждый пиксель будет иметь 4 числа: красный, зеленый, синий, альфа. Давайте просто посмотрим на упрощенную версию, где пиксели всего 1 номер.

Предположим, что исходное изображение: 0 | 100 | 255

Обычный размер холста drawImage приведет либо к 0 | 100 или 0 | 255

Это иногда прекрасно, но он теряет детали, и это может быть очень уродливое и неровное изображение. Если вы думаете об этом, сумма всего цвета в оригинале равна 355 (0 + 100 + 255), оставив средний пиксель 118.33. Средний размер пикселя будет равен 50 или 127,5, что может выглядеть хорошо или очень сильно!

Алгоритм изображения, реализованный в limby-resize, создаст аналогичное изображение для imagemagick, сохраняя все пиксельные данные, поэтому средний пиксель будет таким же.

Наш алгоритм создаст следующее изображение: 33 | 201,3

(0 *.66 + 100 *.33) | (100 *.33 + 255 *.66)

Сумма в нашем случае равна 234,3, оставляя среднее значение 117,15, которое будет равно первому изображению (если в этом примере мы не округлили до 2 десятичных знаков).

Поддержка браузера

canvas_resize.js должен быть включен во внешний интерфейс для лучшего изменения размера клиентской части.

var img, canvas, resized;
img = new Image;
img.onload = function(){
  canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
  resized = document.createElement('canvas');
  resized.width = 300;
  resized.height = 500;
  // see lib/canvas_resize for window.canvasResize = function(){...}
  canvasResize(canvas, resized);
  // resized will now be a properly resized version of canvas
}

img.src = '/path/to/img.jpg';

Ответ 3

Я не уверен, что используется под обложками, но я всегда думал, что У Processing.js есть довольно приличный размер изображения, В документации есть несколько примеров использования. ( Обновить: глядя на код для изменения размера, похоже, что он выполняет похожий процесс с тем, что вы делаете. За исключением того, что он берет данные с одного изображения и перемещает их в другое.)

Еще одна вещь, которую следует учитывать при изменении размера, - это, если возможно, половину размера изображения, чтобы ваши пиксели выглядели лучше. Примерами идеальных размеров будут 50%, 25% и т.д.