Obraz HTML5 Canvas Resize (Downscale) Obraz wysokiej jakości?

Używam elementów płótna html5 do zmiany rozmiaru obrazów w mojej przeglądarce. Okazuje się, że jakość jest bardzo niska. Znalazłem to:Wyłącz interpolację podczas skalowania <kanałów> ale to nie pomaga zwiększyć jakość.

Poniżej znajduje się mój kod css i js, a także obraz przestrzelony w Photoshopie i skalowany w interfejsie API kanwy.

Co muszę zrobić, aby uzyskać optymalną jakość podczas skalowania obrazu w przeglądarce?

Uwaga: Chcę zmniejszyć duży obraz do małego, zmodyfikować kolor na płótnie i wysłać wynik z obszaru roboczego na serwer.

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);
});

Obraz zmieniony w Photoshopie:

Obraz zmieniony na płótnie:

Edytować:

Próbowałem skalować w dół w więcej niż jednym kroku, jak zaproponowano w:

Zmiana rozmiaru obrazu na płótnie HTML5 iHtml5 canvas drawImage: jak zastosować wygładzanie krawędzi

To jest funkcja, której użyłem:

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);


}

Oto wynik, jeśli użyję rozmiaru 2-stopniowego:

Oto wynik, jeśli użyję rozmiaru 3-stopniowego:

Oto wynik, jeśli użyję 4 stopniowej zmiany rozmiaru:

Oto wynik, jeśli użyję 20 stopniowej zmiany rozmiaru:

Uwaga: Okazuje się, że od 1 kroku do 2 kroków występuje znaczna poprawa jakości obrazu, ale im więcej kroków dodajesz do procesu, tym bardziej staje się on niewyraźny.

Czy istnieje sposób na rozwiązanie problemu, który powoduje, że obraz staje się bardziej zamazany w miarę dodawania kolejnych kroków?

Edytuj 2013-10-04: Spróbowałem algorytmu GameAlchemist. Oto wynik w porównaniu z Photoshopem.

Zdjęcie PhotoShop:

Algorytm GameAlchemist:

questionAnswers(12)

yourAnswerToTheQuestion