2012-09-21 27 views
2

更新:一旦我得到這個演示工作...神聖煙霧,它是慢的,只有一個級別2渲染12-16秒(當圖像大約是1000x2000像素)。這甚至不值得打擾。如何在每次畫布轉換後實現Lanczos重採樣而不必製作新畫布?

我發現在上面的答案在這裏這真的真棒,希望尋找代碼:Resizing an image in an HTML5 canvas

//returns a function that calculates lanczos weight 
function lanczosCreate(lobes){ 
    return function(x){ 
    if (x > lobes) 
     return 0; 
    x *= Math.PI; 
    if (Math.abs(x) < 1e-16) 
     return 1 
    var xx = x/lobes; 
    return Math.sin(x) * Math.sin(xx)/x/xx; 
    } 
} 

//elem: canvas element, img: image element, sx: scaled width, lobes: kernel radius 
function thumbnailer(elem, img, sx, lobes){ 
    this.canvas = elem; 
    elem.width = img.width; 
    elem.height = img.height; 
    elem.style.display = "none"; 
    this.ctx = elem.getContext("2d"); 
    this.ctx.drawImage(img, 0, 0); 
    this.img = img; 
    this.src = this.ctx.getImageData(0, 0, img.width, img.height); 
    this.dest = { 
     width: sx, 
     height: Math.round(img.height * sx/img.width), 
    }; 
    this.dest.data = new Array(this.dest.width * this.dest.height * 3); 
    this.lanczos = lanczosCreate(lobes); 
    this.ratio = img.width/sx; 
    this.rcp_ratio = 2/this.ratio; 
    this.range2 = Math.ceil(this.ratio * lobes/2); 
    this.cacheLanc = {}; 
    this.center = {}; 
    this.icenter = {}; 
    setTimeout(this.process1, 0, this, 0); 
} 

thumbnailer.prototype.process1 = function(self, u){ 
    self.center.x = (u + 0.5) * self.ratio; 
    self.icenter.x = Math.floor(self.center.x); 
    for (var v = 0; v < self.dest.height; v++) { 
     self.center.y = (v + 0.5) * self.ratio; 
     self.icenter.y = Math.floor(self.center.y); 
     var a, r, g, b; 
     a = r = g = b = 0; 
     for (var i = self.icenter.x - self.range2; i <= self.icenter.x + self.range2; i++) { 
      if (i < 0 || i >= self.src.width) 
       continue; 
      var f_x = Math.floor(1000 * Math.abs(i - self.center.x)); 
      if (!self.cacheLanc[f_x]) 
       self.cacheLanc[f_x] = {}; 
      for (var j = self.icenter.y - self.range2; j <= self.icenter.y + self.range2; j++) { 
       if (j < 0 || j >= self.src.height) 
        continue; 
       var f_y = Math.floor(1000 * Math.abs(j - self.center.y)); 
       if (self.cacheLanc[f_x][f_y] == undefined) 
        self.cacheLanc[f_x][f_y] = self.lanczos(Math.sqrt(Math.pow(f_x * self.rcp_ratio, 2) + Math.pow(f_y * self.rcp_ratio, 2))/1000); 
       weight = self.cacheLanc[f_x][f_y]; 
       if (weight > 0) { 
        var idx = (j * self.src.width + i) * 4; 
        a += weight; 
        r += weight * self.src.data[idx]; 
        g += weight * self.src.data[idx + 1]; 
        b += weight * self.src.data[idx + 2]; 
       } 
      } 
     } 
     var idx = (v * self.dest.width + u) * 3; 
     self.dest.data[idx] = r/a; 
     self.dest.data[idx + 1] = g/a; 
     self.dest.data[idx + 2] = b/a; 
    } 

    if (++u < self.dest.width) 
     setTimeout(self.process1, 0, self, u); 
    else 
     setTimeout(self.process2, 0, self); 
}; 
thumbnailer.prototype.process2 = function(self){ 
    self.canvas.width = self.dest.width; 
    self.canvas.height = self.dest.height; 
    self.ctx.drawImage(self.img, 0, 0); 
    self.src = self.ctx.getImageData(0, 0, self.dest.width, self.dest.height); 
    var idx, idx2; 
    for (var i = 0; i < self.dest.width; i++) { 
     for (var j = 0; j < self.dest.height; j++) { 
      idx = (j * self.dest.width + i) * 3; 
      idx2 = (j * self.dest.width + i) * 4; 
      self.src.data[idx2] = self.dest.data[idx]; 
      self.src.data[idx2 + 1] = self.dest.data[idx + 1]; 
      self.src.data[idx2 + 2] = self.dest.data[idx + 2]; 
     } 
    } 
    self.ctx.putImageData(self.src, 0, 0); 
    self.canvas.style.display = "block"; 
} 

...

img.onload = function() { 
    var canvas = document.createElement("canvas"); 
    new thumbnailer(canvas, img, 188, 3); //this produces lanczos3 
    //but feel free to raise it up to 8. Your client will appreciate 
    //that the program makes full use of his machine. 
    document.body.appendChild(canvas); 
} 

然而,這種實現加載一個圖像渲染,結束故事。

我一直在試圖重新實現此代碼,以便在每次對現有畫布進行縮放(想象,放大和縮小圖像或文檔)時都進行過濾,而無需加載新圖像或創建新的畫布。

我該如何適應這種工作方式?或者甚至有可能?

回答

0

你想要做的就像singleton重用你的畫布對象。這會讓您節省每次創建新畫布對象的成本,並且您將重複使用同一個對象。

function getCanvas(){ 
    var canvas; 
    if (typeof canvas === "undefined"){ canvas = document.createElement("canvas");} 
    return canvas; 
} 
img.onload = function() { 
    var canvas = getCanvas("canvas"); 
    .... THE REST OF YOUR CODE ....... 
} 

但是這不是什麼減慢你的代碼,圖像縮放算法是非常沉重的算法與密集的CPU使用「通常利用GPU加速在一個非常低的水平」,並使用先進的技術,如multiple buffer r和讓其他人。這裏是關於圖像縮放如何工作的interesting tutorial in java.net,它是用java編寫的,但你可以內插到任何語言。

JavaScript是沒有爲此做好準備技術,所以我建議你使用transformations可在畫布API,在你閱讀的有效途徑是使用canvas2Dcontext教程。

var ctx = canvas.getContext("2d"); 
ctx.scale(2,2); 
+0

謝謝,與畫布轉換的問題是,雖然他們的工作,質量很差。假設過濾可以使質量更好,例如使較大級別的掃描文檔更易讀。不過,你是對的,它太慢了。 – BigOmega