Как бороться с getImageData на границах в Firefox? - PullRequest
0 голосов
/ 31 января 2011

В настоящее время я пишу небольшое приложение для рисования, которое нуждается в доступе к пиксельным данным для своих инструментов размытия и размытия и столкнулось с неприятной проблемой HTML5 Canvas API в Firefox. Очевидно, он не реализует getImageData, как определено в спецификации. Спецификация специально гласит:"... Пиксели вне холста должны возвращаться как прозрачный черный. ...".

Этого не происходит в FF (протестировано в FF 3.6 и 4 beta 9). Вместо этого он выдаст ошибку, такую ​​как это: неверная или недопустимая строка была указана "code:" 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);
            },

Это не круто, так как я возвращаю кучу пустых пикселей вызывающей стороне. Было бы намного лучше возвращать результаты, как в спецификации.

Просто для пояснения кода является частью Context API, который оборачивает реальный контекст и предоставляет некоторые дополнительные функции (относительные координаты и т. Д.). Это, вероятно, объясняет, откуда взялись такие вещи, как this.width и т. Д.

Это часть XXX, которая вызывает беспокойство. Мне просто нужен какой-то способ вернуть ImageData, который соответствует спецификации. Любые идеи о том, как это сделать, приветствуются. :)

Ответы [ 2 ]

1 голос
/ 01 февраля 2011

Возможно, вы могли бы создать холст размером d на d и нарисовать на нем соответствующую часть оригинального холста?К сожалению, вы не можете нарисовать исходный холст напрямую, потому что вы наткнулись на тот же самый код проверки границ, поэтому вам нужно выяснить, какое перекрытие.а не Firefox.

Кстати, это Mozilla bug 392751 .

0 голосов
/ 15 февраля 2011

Я решил использовать следующий фрагмент, чтобы обойти проблему.Надеюсь, кто-то найдет это полезным ...

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