2011-01-31 80 views
0

我目前正在編寫一個小圖形應用程序,需要爲它的污跡和模糊工具訪問像素數據,並在Firefox中使用HTML5 Canvas API遇到了一個令人討厭的問題。顯然它並沒有按照規範中的定義實現getImageData。 spec specifically says「...畫布外的像素必須以透明黑色的形式返回......」。如何在Firefox中處理getImageData邊界?

這在FF中沒有發生(在FF 3.6和4 beta 9中測試過)。相反,它會給出一個錯誤,如本:指定無效或非法字符串「代碼:」 12

注意,這似乎在Chrome就好了工作。

我想這意味着我將不得不實施一些額外的代碼來解決這個限制。我設法繞過使用以下代碼的問題:

  getImageDataAround: function(p, r) { 
       p = this._toAbsolute(p); 
       r = this._toAbsolute(r); 

       p = p.sub(r); 

       var d = r * 2; 
       var width = d; 
       var height = d; 

       // XXX: FF hack 
       if(navigator.userAgent.indexOf('Firefox') != -1) { 
        if(p.x < 0) { 
         width += p.x; 
         p.x = 0; 
        } 

        if(p.y < 0) { 
         height += p.y; 
         p.y = 0; 
        } 

        var x2 = p.x + width; 
        if(x2 >= this.width) { 
         width = d - (x2 - this.width); 
        } 

        var y2 = p.y + height; 
        if(y2 >= this.height) { 
         height = d - (y2 - this.height); 
        } 

        if((width != d) || (height != d)) { 
         // XXX: not ideal but at least this won't give any 
         // errors 
         return this.ctx.createImageData(d, d); 
        } 
       } 

       return this.ctx.getImageData(p.x, p.y, width, height); 
      }, 

這不是很酷,因爲我向調用方返回一堆空像素。返回結果就像在規範中那樣更好。

只是爲了澄清的代碼是一個上下文API,它包裝真實上下文並提供了一些額外的功能(相對COORDS等)的一部分。這可能解釋了諸如this.width等來自哪裏。

這是XXX的麻煩部分。我只需要一些方法來返回符合規格的ImageData。任何想法如何做到這一點都是值得歡迎的。 :)

回答

1

也許你可以通過d創建一個尺寸爲d的畫布,並將原始畫布的相應部分繪製到它上面?可悲的是,你不能直接繪製原始畫布,因爲你遇到了相同的邊界檢查代碼,所以你必須找出重疊。

你應該考慮嗅探Gecko而不是Firefox。

順便提一下,這是Mozilla bug 392751

+0

是的。我想沒有其他辦法了......這是一個遺憾,他們還沒有修復它(錯誤報告是從2007年起!)。我將繼續討論這個問題一段時間以獲得一些其他想法。如果什麼都沒有出現,我會接受你的答案。 :)關於嗅探的好處! – 2011-02-01 05:53:19

0

我最終使用下面的代碼片段來解決這個問題。希望有人認爲它有用...

var getImageDataAround = function(ctx, p, r) { 
    // ctx: HTML5 Canvas 2D context 
    // p: {x: 23, y: 37} 
    // r: radius in px 

    // FF fails with fractional values 
    p.x = Math.round(p.x); 
    p.y = Math.round(p.y); 
    r = parseInt(r); 

    p.x -= r; 
    p.y -= r; 

    var d = r * 2; 
    var width = d; 
    var height = d; 

    // FF fails at bounds 
    if(navigator.userAgent.indexOf('Gecko') != -1) { 
     var xOffset = 0; 
     var yOffset = 0; 

     if(p.x < 0) { 
      xOffset = -p.x; 
      width += p.x; 
      p.x = 0; 
     } 

     if(p.y < 0) { 
      yOffset = -p.y; 
      height += p.y; 
      p.y = 0; 
     } 

     var x2 = p.x + width; 
     if(x2 >= ctx.canvas.width) { 
      width = d - (x2 - ctx.canvas.width); 
     } 

     var y2 = p.y + height; 
     if(y2 >= ctx.canvas.height) { 
      height = d - (y2 - ctx.canvas.height); 
     } 

     if((width != d) || (height != d)) { 
      var data = ctx.createImageData(d, d); 

      if(xOffset >= d || yOffset >= d || 
        width < 1 || height < 1) { 
       // totally outside of bounds 
       return data; 
      } 

      var originalData = ctx.getImageData(p.x, p.y, 
       width, height); 
      var pos = 4 * (xOffset + d * yOffset); 
      var dataLen = 4 * d * (yOffset + height); 

      for(var originalPos = 0, x = xOffset; 
        pos < dataLen; 
        pos += 4, originalPos += 4, x++) { 
       if(x == d) { 
        x = xOffset; 
        pos += xOffset * 4; 
       } 

       if(xOffset <= x && x < width + xOffset) { 
        data.data[pos] = originalData.data[originalPos]; 
        data.data[pos + 1] = originalData.data[originalPos + 1]; 
        data.data[pos + 2] = originalData.data[originalPos + 2]; 
        data.data[pos + 3] = originalData.data[originalPos + 3]; 
       } 
       else { 
        originalPos -= 4; 
       } 
      } 

      return data; 
     } 
    } 

    return ctx.getImageData(p.x, p.y, width, height); 
}