【问题标题】:How to deal with getImageData at bounds in Firefox?如何在 Firefox 中处理 getImageData 边界?
【发布时间】:2011-06-18 20:08:48
【问题描述】:

我目前正在编写一个小型绘图应用程序,该应用程序需要访问其涂抹和模糊工具的像素数据,但在 Firefox 中遇到了 HTML5 Canvas API 的一个令人讨厌的问题。显然,它并没有完全按照规范中的定义实现 getImageData。 spec specifically says“...画布外的像素必须返回为透明黑色。...”。

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

这并不酷,因为我将一堆空像素返回给调用者。像规范一样返回结果会更好。

只是为了澄清代码是 Context API 的一部分,它包装了真实的上下文并提供了一些额外的功能(相对坐标等)。这可能解释了 this.width 等内容的来源。

麻烦的是XXX部分。我只需要某种方法来返回符合规范的 ImageData。欢迎任何关于如何做到这一点的想法。 :)

【问题讨论】:

    标签: javascript html firefox html5-canvas getimagedata


    【解决方案1】:

    也许您可以创建一个 d 乘 d 大小的画布,然后在其上绘制原始画布的适当部分?遗憾的是,您无法直接绘制原始画布,因为您遇到了相同类型的边界检查代码,因此您必须找出重叠。

    您应该考虑嗅探Gecko 而不是 Firefox。

    顺便说一下,这里是 Mozilla bug 392751

    【讨论】:

    • 是的。我想没有其他办法......很遗憾他们还没有修复它(错误报告来自 2007 年!)。我将保持这个问题开放一段时间以获得其他想法。如果没有任何问题,我会接受你的回答。 :) 关于嗅探的好点!
    【解决方案2】:

    我最终使用了以下 sn-p 来解决这个问题。希望有人觉得它有用...

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

    【讨论】:

      猜你喜欢
      • 2014-11-08
      • 1970-01-01
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2017-03-11
      • 1970-01-01
      • 2012-11-21
      • 2018-11-30
      相关资源
      最近更新 更多