Uso elementi canvas html5 per ridimensionare le immagini nel mio browser. Si scopre che la qualità è molto bassa. Ho trovato questo: disabilita l'interpolazione quando ridimensiona un <canvas> ma non aiuta ad aumentare la qualità.
Di seguito è riportato il mio codice CSS e JS, nonché l'immagine scaricata con Photoshop e ridimensionata nell'API di tela.
Cosa devo fare per ottenere una qualità ottimale durante il ridimensionamento di un'immagine nel browser?
Nota: desidero ridimensionare un'immagine grande in una piccola, modificare il colore in una tela e inviare il risultato dalla tela al server.
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);
});
L'immagine ridimensionata con Photoshop:
L'immagine ridimensionata su tela:
Modificare:
Ho cercato di effettuare il downscaling in più di un passaggio, come proposto in:
Ridimensionamento di un'immagine in una tela HTML5 e disegno su tela HTML5 Immagine: come applicare l'antialias
Questa è la funzione che ho usato:
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);
}
Ecco il risultato se uso un ridimensionamento in due passaggi:
Ecco il risultato se uso un ridimensionamento in 3 passaggi:
Ecco il risultato se uso un ridimensionamento in 4 step:
Ecco il risultato se uso un ridimensionamento di 20 step:
Nota: si scopre che da 1 passaggio a 2 passaggi si ha un notevole miglioramento della qualità dell'immagine, ma più passaggi si aggiungono al processo, più l'immagine diventa sfocata.
C'è un modo per risolvere il problema che l'immagine diventa più sfocata più passaggi aggiungi?
Modifica 04-10-2013: ho provato l'algoritmo di GameAlchemist. Ecco il risultato rispetto a Photoshop.
Immagine di PhotoShop:
Algoritmo di GameAlchemist: