2012-09-30 85 views
2

只是想知道是否有人已經在Javascript中完成了這項工作,或者如果我必須自己做 - 如果後者:我該怎麼做? (不要求一段代碼,只是好奇哪一種方法,你會使用)JavaScript中是否存在getColorBoundsRect()等價物?

+0

你或許應該說明你想在這裏,而不是做的只是鏈接到一些外部網站的內容。如果該網站更改其網址或脫機,您的問題將無法理解。 – Pointy

+0

一個人不需要這個鏈接 - 我認爲這將是很好的指出我需要它,但我可以刪除它;) – Peter

回答

2

我有更好的解。沒有必要遍歷整個像素,只能通過邊界框外的遍歷。想想這樣,如果你想在1D中做同樣的事情:在數組中找到一個值的第一個和最後一個位置,你是否會遍歷整個數組?最好從頭開始,直到找到第一個值,然後從結束開始,直到找到最後一個值。以下代碼對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的)太:

module.RGBToHex = function(rgb) { 
    return (rgb.a << 24 | rgb.r<<16 | rgb.g<<8 | rgb.b) >>> 0; 
}; 
+0

顯然是一個更美麗的版本 - 非常感謝;) – Peter

1

這裏是我的quick'n'dirty解決方案,也許somebody'll覺得有用;)

/** 
* 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; 
    } 
} 
相關問題