0

私は現在、スマッジツールとブラーツールのピクセルデータにアクセスする必要がある小さな描画アプリケーションを作成しており、FirefoxのHTML5CanvasAPIで厄介な問題にぶつかりました。どうやらそれは仕様で定義されているようにgetImageDataを完全に実装していません。仕様には、「...キャンバスの外側のピクセルは透明な黒として返される必要があります...」と具体的に記載されています。

これはFFでは発生しません(FF 3.6および4ベータ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の一部です。これはおそらく、this.widthなどがどこから来ているのかを説明しています。

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

4

2 に答える 2

1

おそらく、サイズd x dのキャンバスを作成し、その上に元のキャンバスの適切な部分を描画することができますか?残念ながら、同じ種類の境界チェックコードに遭遇したため、元のキャンバスを直接描画することはできません。そのため、オーバーラップを把握する必要があります。

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

By the way, this is Mozilla bug 392751.

于 2011-02-01T00:37:04.057 に答える
0

I ended up using following snippet to work around the issue. Hopefully someone finds it useful...

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);
}
于 2011-02-15T14:40:39.953 に答える