Jak skalować obrazy na płótnie html5 z lepszą interpolacją?

Po pierwsze: co próbuję zrobić?

Mam aplikację do przeglądania obrazów. Używa elementu canvas do renderowania obrazu. Możesz powiększyć, możesz pomniejszyć i przeciągnąć dookoła. Ta część działa teraz doskonale.

Ale powiedzmy, że mam obraz z dużą ilością tekstu. Ma rozdzielczość 1200x1700, a moje płótno ma 1200x900. Początkowo przy pomniejszeniu prowadzi to do renderowanej rozdzielczości ~ 560x800.

Mój rzeczywisty rysunek wygląda tak:

drawImage(src, srcOffsetX, srcOffsetY, sourceViewWidth, sourceViewHeight,
destOffsetX, destOffsetY, destWidth, destHeight);

Mały tekst na tym obrazie wygląda naprawdę, bardzo źle, zwłaszcza w porównaniu z innymi przeglądarkami obrazów (np. IrfanView) lub nawet elementem html <img>.

Zorientowałem się, że przyczyną tego problemu jest algorytm interpolacji przeglądarek. Porównanie różnych przeglądarek wykazało, że Chrome wyświetla najlepiej skalowane obrazy, ale wciąż nie jest wystarczająco dobry.

Szukałem w każdym zakątku Interwebs prosto przez 4-5 godzin i nie znalazłem tego, czego potrzebuję. Znalazłem opcję „imageSmoothingEnabled”, style CSS „renderowania obrazów”, których nie można używać na płótnie, renderowania na pozycjach float i wielu implementacjach algorytmów interpolacji w JavaScript (są todaleko spowolnić dla mojego celu).

Możesz zapytać, dlaczego ci to wszystko mówię: aby zaoszczędzić ci czasu na udzielenie mi odpowiedzi, które już znam

Więc: jestkażdy dobry i szybki sposób na lepszą interpolację? Moim obecnym pomysłem jest stworzenie obiektu obrazu, zmiana jego rozmiaru (ponieważ img ma dobrą interpolację po przeskalowaniu!) I renderuje go. Niestety, zastosowanie img.width wydaje się tylko wpływać na wyświetlaną szerokość ...

Aktualizacja: Dzięki Simonowi mogłem rozwiązać mój problem. Oto algorytm skalowania dynamicznego, którego użyłem. Zauważ, że zachowuje proporcje, parametr wysokości służy tylko do unikania obliczeń pływakowych. Teraz tylko się skaluje.

scale(destWidth, destHeight){
        var start = new Date().getTime();
        var scalingSteps = 0;
        var ctx = this._sourceImageCanvasContext;
        var curWidth = this._sourceImageWidth;
        var curHeight = this._sourceImageHeight;

        var lastWidth = this._sourceImageWidth;
        var lastHeight = this._sourceImageHeight;

        var end = false;
        var scale=0.75;
        while(end==false){
            scalingSteps +=1;
            curWidth *= scale;
            curHeight *= scale;
            if(curWidth < destWidth){
                curWidth = destWidth;
                curHeight = destHeight;
                end=true;
            }
            ctx.drawImage(this._sourceImageCanvas, 0, 0, Math.round(lastWidth), Math.round(lastHeight), 0, 0, Math.round(curWidth), Math.round(curHeight));
            lastWidth = curWidth;
            lastHeight = curHeight;
        }
        var endTime =new Date().getTime();
        console.log("execution time: "+ ( endTime - start) + "ms. scale per frame: "+scale+ " scaling step count: "+scalingSteps);
    }

questionAnswers(1)

yourAnswerToTheQuestion