Utilizo elementos de lienzo html5 para cambiar el tamaño de las imágenes en mi navegador. Resulta que la calidad es muy baja. Encontré esto: deshabilite la interpolación al escalar un <canvas> pero no ayuda a aumentar la calidad.
A continuación se muestra mi código css y js, así como la imagen escaldada con Photoshop y escalada en la API de lienzo.
¿Qué debo hacer para obtener una calidad óptima al escalar una imagen en el navegador?
Nota: Quiero reducir una imagen grande a una pequeña, modificar el color en un lienzo y enviar el resultado del lienzo al servidor.
CSS:
canvas, img {
image-rendering: optimizeQuality;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
-ms-interpolation-mode: nearest-neighbor;
}
JS:
var $img = $('<img>');
var $originalCanvas = $('<canvas>');
$img.load(function() {
var originalContext = $originalCanvas[0].getContext('2d');
originalContext.imageSmoothingEnabled = false;
originalContext.webkitImageSmoothingEnabled = false;
originalContext.mozImageSmoothingEnabled = false;
originalContext.drawImage(this, 0, 0, 379, 500);
});
La imagen cambió de tamaño con Photoshop:
La imagen redimensionada en lienzo:
Editar:
Traté de reducir la escala en más de un paso como se propuso en:
Cambiar el tamaño de una imagen en un lienzo HTML5 y un lienzo Html5 drawImage: cómo aplicar el antialiasing
Esta es la función que he usado:
function resizeCanvasImage(img, canvas, maxWidth, maxHeight) {
var imgWidth = img.width,
imgHeight = img.height;
var ratio = 1, ratio1 = 1, ratio2 = 1;
ratio1 = maxWidth / imgWidth;
ratio2 = maxHeight / imgHeight;
// Use the smallest ratio that the image best fit into the maxWidth x maxHeight box.
if (ratio1 < ratio2) {
ratio = ratio1;
}
else {
ratio = ratio2;
}
var canvasContext = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
var copyContext = canvasCopy.getContext("2d");
var canvasCopy2 = document.createElement("canvas");
var copyContext2 = canvasCopy2.getContext("2d");
canvasCopy.width = imgWidth;
canvasCopy.height = imgHeight;
copyContext.drawImage(img, 0, 0);
// init
canvasCopy2.width = imgWidth;
canvasCopy2.height = imgHeight;
copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
var rounds = 2;
var roundRatio = ratio * rounds;
for (var i = 1; i <= rounds; i++) {
console.log("Step: "+i);
// tmp
canvasCopy.width = imgWidth * roundRatio / i;
canvasCopy.height = imgHeight * roundRatio / i;
copyContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvasCopy.width, canvasCopy.height);
// copy back
canvasCopy2.width = imgWidth * roundRatio / i;
canvasCopy2.height = imgHeight * roundRatio / i;
copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
} // end for
// copy back to canvas
canvas.width = imgWidth * roundRatio / rounds;
canvas.height = imgHeight * roundRatio / rounds;
canvasContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvas.width, canvas.height);
}
Aquí está el resultado si uso un tamaño de 2 pasos:
Aquí está el resultado si uso un tamaño de 3 pasos:
Aquí está el resultado si uso un tamaño de 4 pasos:
Aquí está el resultado si uso un tamaño reducido de 20 pasos:
Nota: Resulta que de 1 paso a 2 pasos hay una gran mejora en la calidad de la imagen, pero cuantos más pasos agregue al proceso, más difusa se volverá la imagen.
¿Hay alguna manera de resolver el problema de que la imagen se vuelve más borrosa a medida que agrega más pasos?
Editar 04-10-2013: probé el algoritmo de GameAlchemist. Aquí está el resultado en comparación con Photoshop.
Imagen de PhotoShop:
Algoritmo de GameAlchemist: