簡體   English   中英

如何使用更好的插值在html5畫布上縮放圖像?

[英]How to scale images on a html5 canvas with better interpolation?

首先:我想做什么?

我有一個查看圖像的應用程序。 它使用canvas元素渲染圖像。 你可以放大,你可以縮小,你可以拖動它。 這部分現在完美運作。

但是,假設我有一個包含大量文本的圖像。 它的分辨率為1200x1700,我的畫布有1200x900。 最初,當縮小時,這會導致渲染分辨率為~560x800。

我的實際繪圖如下:

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

此圖像上的小文字看起來非常非常糟糕,特別是與其他圖像查看器(例如IrfanView)或甚至html <img>元素相比時。

我發現瀏覽器插值算法是導致這個問題的原因。 比較不同的瀏覽器顯示,Chrome渲染縮放圖像效果最佳,但仍然不夠好。

好吧,我在Interwebs的每個角落搜索了4-5個小時,沒找到我需要的東西。 我找到了“imageSmoothingEnabled”選項,“圖像渲染”CSS樣式,你不能在畫布上使用,在浮動位置渲染和插值算法的許多JavaScript實現(這些我的目的慢)。

你可能會問為什么我告訴你這一切:為了節省你給我答案的時間我已經知道了

那么:有沒有更好的快速方法來獲得更好的插值? 我目前的想法是創建一個圖像對象,調整大小(因為img在縮放時具有良好的插值!)然后渲染它。 不幸的是,應用img.width似乎只會影響顯示的寬度......

更新 :感謝西蒙,我可以解決我的問題。 這是我使用的動態縮放算法。 請注意,它保持縱橫比,height參數僅用於避免更多的浮點計算。 它現在只縮小。

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

你需要多次“下台”。 您需要將其重新縮放到中間大小,而不是從非常大的圖像縮放到非常小的圖像。

考慮要以1/6比例繪制的圖像。 你可以這樣做:

var w = 1280;
var h = 853;

ctx.drawImage(img, 0, 0, w/6, h/6);   

或者你可以將其繪制為1/2刻度的內存畫布,然后再繪制1/2刻度,然后再刻度1/2刻度。 結果是1/6比例的圖像,但我們使用三個步驟:

var can2 = document.createElement('canvas');
can2.width = w/2;
can2.height = w/2;
var ctx2 = can2.getContext('2d');

ctx2.drawImage(img, 0, 0, w/2, h/2);
ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4);
ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6);

然后,您可以將其繪制回原始上下文:

ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6);

你可以看到現場的差異,這里:

 var can = document.getElementById('canvas1'); var ctx = can.getContext('2d'); var img = new Image(); var w = 1280; var h = 853; img.onload = function() { // step it down only once to 1/6 size: ctx.drawImage(img, 0, 0, w/6, h/6); // Step it down several times var can2 = document.createElement('canvas'); can2.width = w/2; can2.height = w/2; var ctx2 = can2.getContext('2d'); // Draw it at 1/2 size 3 times (step down three times) ctx2.drawImage(img, 0, 0, w/2, h/2); ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4); ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6); ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6); } img.src = 'http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Equus_quagga_%28Namutoni%2C_2012%29.jpg/1280px-Equus_quagga_%28Namutoni%2C_2012%29.jpg' 
 canvas { border: 1px solid gray; } 
 <canvas id="canvas1" width="400" height="400"></canvas> 

在jsfiddle上查看相同的片段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM