2011-01-31 12 views
0

私は現在、汚れやぼかしツールのためにピクセルデータにアクセスし、FirefoxのHTML5 Canvas APIで厄介な問題にぶつかってしまう小さな描画アプリケーションを作成しています。明らかに、仕様で定義されているgetImageDataは実装されていません。 spec specifically says "...キャンバスの外側にあるピクセルは透明な黒として返さなければなりません。"Firefoxの境界でgetImageDataを処理する方法は?

FFでは発生しません(FF 3.6および4ベータ9でテスト済み)。その代わりに、このようなエラーを与える:これはChromeでうまく動作するように表示されていることを12

注:無効または不正な文字列が「コード」に指定されました。

これは、この制限を回避するためにいくつかの特別なコードを実装する必要があることを意味します。

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

私は空のピクセルの束を呼び出し元に戻すので、これはクールではありません。スペックのように結果を返すのがより良い方法です。

ただ、コードを明確にするには、実際のコンテキストをラップし、いくつかの追加機能(相対COORDSなど)を提供し、コンテキストAPIの一部です。おそらくthis.widthなどがどこから来たのか分かります。

これは面倒なXXXの部分です。 ImageDataを返すためには、仕様に合った方法が必要です。これを行う方法に関するアイデアは大歓迎です。 :)

答えて

1

はおそらく、あなたはdだけサイズdのキャンバスを作成し、それへのオリジナルキャンバスの適切な部分を描くことができますか?悲しいことに、元のキャンバスを直接描画することはできません。なぜなら、同じ種類の境界チェックコードを実行するため、オーバーラップを把握する必要があるからです。

あなたはGeckoではなく、Firefox用のスニッフィングを検討する必要があります。

ところで、これは、Mozilla bug 392751です。

+0

うん...それは重宝します。私は他の方法はないと思う...彼らがまだそれを修正していないのは残念だ(バグ報告は2007年だ!)。私はいくつかの他のアイデアを得るためにこの質問をしばらく開いておくつもりです。何も来なければ、私はあなたの答えを受け入れるでしょう。 :)スニッフィングについての良い点! –

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); 
} 
関連する問題