Wie skaliere ich Bilder auf einer HTML5-Leinwand mit besserer Interpolation?

Zuallererst: Was versuche ich zu tun?

Ich habe eine Anwendung zum Anzeigen von Bildern. Es verwendet das canvas-Element, um das Bild zu rendern. Sie können vergrößern, verkleinern und verschieben. Dieser Teil funktioniert gerade perfekt.

Angenommen, ich habe ein Bild mit viel Text. Es hat eine Auflösung von 1200x1700 und meine Leinwand hat 1200x900. Beim Verkleinern ergibt sich zunächst eine gerenderte Auflösung von ~ 560x800.

Meine aktuelle Zeichnung sieht so aus:

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

Kleiner Text auf diesem Bild sieht wirklich sehr, sehr schlecht aus, insbesondere im Vergleich zu anderen Bildbetrachtern (z. B. IrfanView) oder sogar dem HTML-Element <img>.

Ich fand heraus, dass der Browser-Interpolationsalgorithmus die Ursache für dieses Problem ist. Der Vergleich verschiedener Browser ergab, dass Chrome skalierte Bilder am besten wiedergibt, aber immer noch nicht gut genug.

Nun, ich habe in jeder Ecke der Interwebs 4-5 Stunden lang gesucht und nicht gefunden, was ich brauche. Ich habe die Option "imageSmoothingEnabled" gefunden, CSS-Stile für die Bildwiedergabe, die Sie auf der Leinwand nicht verwenden können, Rendering an Float-Positionen und viele JavaScript-Implementierungen von Interpolationsalgorithmen (das sindweit zu langsam für meinen Zweck).

Sie fragen sich vielleicht, warum ich Ihnen das alles erzähle: um Ihnen die Zeit zu sparen, mir Antworten zu geben, die ich bereits kenne

Also: ist dairgendein Guter und schneller Weg zu einer besseren Interpolation? Meine aktuelle Idee ist es, ein Bildobjekt zu erstellen, dessen Größe zu ändern (da img beim Skalieren eine gute Interpolation aufweist!) Und es dann zu rendern. Leider scheint das Anwenden von img.width nur die angezeigte Breite zu beeinflussen ...

Aktualisieren: Dank Simon konnte ich mein Problem lösen. Hier ist der dynamische Skalierungsalgorithmus, den ich verwendet habe. Beachten Sie, dass das Seitenverhältnis beibehalten wird. Der Parameter height dient nur dazu, mehr Float-Computing zu vermeiden. Es wird jetzt nur verkleinert.

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

Antworten auf die Frage(1)

Ihre Antwort auf die Frage