2

只是想知道是否有人已经用 Javascript 完成了这项工作,或者我是否必须自己做——如果是后者:我将如何做?(不要求一段代码,只是好奇你会使用哪种方法)

4

2 回答 2

2

我有更好的解决方案。不必遍历所有像素,只需遍历边界框外的像素即可。这样想,如果你想在一维中做同样的事情:在数组中找到一个值的第一个和最后一个位置,你会遍历整个数组吗?最好从头开始直到找到第一个值,然后从结尾遍历直到找到最后一个值。以下代码对 2D 执行相同的操作。我还没有彻底测试过它(无论是正确性还是速度),但它似乎有效,而且常识说它更快。

BitmapData.prototype.getColorBoundsRect = function(mask, color, findColor, rect){
    findColor = typeof findColor !== 'undefined' ? findColor : true;
    rect = typeof rect !== 'undefined' ? rect : new module.Rect(0, 0, this.width, this.height);

    var l = rect.w - 1;
    var r = 0;
    var t = rect.h - 1;
    var b = 0;

    var data = this.context.getImageData(rect.x, rect.y, rect.w, rect.h).data;

    // Scan from top to first pixel.
    for (var i = 0; i < data.length; i += 4){
        var val = module.RGBToHex({r:data[i], g:data[i+1], b:data[i+2], a:data[i+3]});
        // console.log(val, mask, color, (val & mask) >>> 0)
        if ((findColor && ((val & mask) >>> 0 == color)) || (!findColor && ((val & mask) >>> 0 != color))){
            l = r = ((i / 4) % rect.w);
            t = b = Math.floor(i / 4 / rect.w);
            break;
        }
    }

    // We found nothing.
    if (i >= data.length) {
        return null;
    }


    // Scan from bottom to first pixel
    for (var j = data.length - 4; j > i; j -= 4){
        var val = module.RGBToHex({r:data[j], g:data[j+1], b:data[j+2], a:data[j+3]});
        if ((findColor && ((val & mask) >>> 0 == color)) || (!findColor && ((val & mask) >>> 0 != color))){
            l = Math.min(l, ((j / 4) % rect.w))
            r = Math.max(r, ((j / 4) % rect.w))
            b = Math.floor(j / 4 / rect.w);
            break;
        }
    }

    console.log(l, r, t, b);

    // Scan from left
    for (var x = 0; x < l; x ++){
        for (var y = t + 1; y <= b; y ++){
            i = (y * rect.w + x) * 4
            var val = module.RGBToHex({r:data[i], g:data[i+1], b:data[i+2], a:data[i+3]});
            if ((findColor && ((val & mask) >>> 0 == color)) || (!findColor && ((val & mask) >>> 0 != color))){
                l = Math.min(l, x);
                break;
            }
        }
    }

    console.log(l, r, t, b);


    // Scan from right
    for (var x = rect.w - 1; x > r; x --){
        for (var y = t; y < b; y ++){
            i = (y * rect.w + x) * 4
            var val = module.RGBToHex({r:data[i], g:data[i+1], b:data[i+2], a:data[i+3]});
            if ((findColor && ((val & mask) >>> 0 == color)) || (!findColor && ((val & mask) >>> 0 != color))){
                r = Math.max(r, x);
                break;
            }
        }
    }

    console.log(l, r, t, b)

    return new module.Rect(l + rect.x, t + rect.y, (r - l), (b - t));
}

在此代码BitmapData中,仅包装了一个画布对象及其 context2d,并且Rect是一个{x: , y: , w: , h: }对象。我不得不对 RGBToHex 进行一些操作,以确保我也得到了正数(uint's):

module.RGBToHex = function(rgb) { 
    return (rgb.a << 24 | rgb.r<<16 | rgb.g<<8 | rgb.b) >>> 0; 
};
于 2013-10-22T14:51:34.097 回答
1

这是我的快速'n'dirty解决方案,也许有人会发现它有用;)

/**
 * get a rectangle around color
 * @param  {...} ctx 2dCanvasObject to be scanned
 * @return {Object}     object storing the rectangle's data (x, y, w(idth), h(eight))
 */
function getColorBoundsRect(ctx) {
    /**
     * the canvas' context's data property (shorthand)
     * @type {...}
     */
    var data = ctx.data,
    /**
     * counter variable
     * @type {Number}
     */
        i = 0,
    /**
     * the "leftest" pixel that is not black (starts right, as we check if currently looped pixel (that is not black) is "lefter" than the current outerLeftPixel)
     * @type {Number}
     */
        outerLeftPixel = w-1,
    /**
     * the "rightest" pixel that is not black (starts left, as we check if currently looped pixel (that is not black) is "righter" than the current outerRightPixel)
     * @type {Number}
     */
        outerRightPixel = 0,
    /**
     * the "toppest" pixel that is not black (starts at bottom, as we check if currently looped pixel (that is not black) is "topper" than the current outerTopPixel)
     * @type {Number}
     */
        outerTopPixel = h-1,
    /**
     * the "bottomest" pixel that is not black (starts at top, as we check if currently looped pixel (that is not black) is "bottomer" than the current outerBottomPixel)
     * @type {Number}
     */
        outerBottomPixel = 0,
    /**
     * x coordinate of currently looped pixel
     * @type {Number}
     */
        x,
    /**
     * y coordinate of currently looped pixel
     * @type {Number}
     */
        y;

    // loop through all pixels
    // i equals the i'th pixel (0 is the upper left pixel, w*h is the bottom right pixel)
    while (i < (data.length / 4)) {
        // check if currently looped pixel is anything else than black --> color
        if ((data[i*4] + data[i*4+1] + data[i*4+2]) > 0) {
            // set coordinates for the currently looped pixel
            x = i % w; // if one row has 10px and i = 35, the x coordinate of the current pixel is 35 % 10 = 5
            y = Math.floor(i / w); // if one row has 10px and i=35, the y coordinate of the current pixel is 35/10 = 3.5 (--> rounded off = 3)

            // if the x coordinate of the current (colored) pixel is smaller than the current "leftest" pixel, set the x coordinate as new "leftest pixel"
            // same procedure for the other values
            if (x < outerLeftPixel) {
                outerLeftPixel = x;
            }
            if (x > outerRightPixel) {
                outerRightPixel = x;
            }
            if (y < outerTopPixel) {
                outerTopPixel = y;
            }
            if (y > outerBottomPixel) {
                outerBottomPixel = y;
            }
        }
        ++i;
    }

    // if there is color on the canvas, the outer[Right|Left|Bottom|Top]Pixel properties should have been updated accordingly and the following condition should be true 
    if (outerRightPixel > outerLeftPixel && outerBottomPixel > outerTopPixel) {
        return {
            x: outerLeftPixel,
            y: outerTopPixel,
            w: outerRightPixel - outerLeftPixel,
            h: outerBottomPixel - outerTopPixel
        };
    } 
    // if there is no color on the canvas, return false, as there is no rectangle
    else {
        return false;
    }
}
于 2012-09-30T14:36:26.247 回答