2014-04-23 59 views
3

我正在尋找一種JavaScript方法來檢測透明PNG內的圖像。例如,我將創建一個帶有940x680透明畫布的PNG,然後在該畫布內放置一個完全不透明的對象。Javascript方法來檢測不透明PNG的區域

我希望能夠檢測的大小(H/W),和該對象的頂部+左的位置,是不畫布

這裏內透明是原始圖像Transparent PNG Canvas with Image Object 下面是一個例子我想實現的一個例子。 (邊框疊加,與頂級+左極限數據)

Results Image

香港專業教育學院發現,確實有些透明檢出的資源了,但是我不知道我怎麼擴大這樣的事情是什麼即時尋找。

var imgData, 
    width = 200, 
    height = 200; 

$('#mask').bind('mousemove', function(ev){ 
    if(!imgData){ initCanvas(); } 
    var imgPos = $(this).offset(), 
     mousePos = {x : ev.pageX - imgPos.left, y : ev.pageY - imgPos.top}, 
     pixelPos = 4*(mousePos.x + height*mousePos.y), 
     alpha = imgData.data[pixelPos+3]; 

    $('#opacity').text('Opacity = ' + ((100*alpha/255) << 0) + '%'); 
}); 

function initCanvas(){ 
    var canvas = $('<canvas width="'+width+'" height="'+height+'" />')[0], 
      ctx = canvas.getContext('2d'); 

    ctx.drawImage($('#mask')[0], 0, 0); 
    imgData = ctx.getImageData(0, 0, width, height); 
} 

Fiddle

回答

7

你需要做的:

  • 獲取緩衝
  • 獲取該緩衝區的32位引用(如果你的其他像素是透​​明的,那麼你可以使用Uint32Array緩衝區來迭代)。
  • 掃描0 - 寬度找到X1邊緣
  • 掃描寬度 - 0找到X2邊緣
  • 掃描0 - 高度找到Y1邊緣
  • 掃描高度 - 0找到Y2邊緣

這些掃描可以合併,但爲了簡單起見,我將分別顯示每一步。

Online demo of this can be found here.

結果:

Snapshot

當圖像加載繪製它(如果圖像較小,則本例中的其餘部分將是浪費,你會知道的座標當繪製它 - 假設在這裏你畫的圖像很大,裏面有一個小圖像)

(注意:這是一個非優化版本爲簡單起見)

ctx.drawImage(this, 0, 0, w, h); 

var idata = ctx.getImageData(0, 0, w, h),  // get image data for canvas 
    buffer = idata.data,      // get buffer (unnes. step) 
    buffer32 = new Uint32Array(buffer.buffer), // get a 32-bit representation 
    x, y,          // iterators 
    x1 = w, y1 = h, x2 = 0, y2 = 0;   // min/max values 

然後掃描每個邊緣。對於左邊緣從0掃描至寬度爲每個線(未優化):

// get left edge 
for(y = 0; y < h; y++) {      // line by line 
    for(x = 0; x < w; x++) {     // 0 to width 
     if (buffer32[x + y * w] > 0) {   // non-transparent pixel? 
      if (x < x1) x1 = x;    // if less than current min update 
     } 
    } 
} 

對於右邊緣你只是負X迭代:

// get right edge 
for(y = 0; y < h; y++) {      // line by line 
    for(x = w; x >= 0; x--) {     // from width to 0 
     if (buffer32[x + y * w] > 0) { 
      if (x > x2) x2 = x; 
     } 
    } 
} 

而同樣是用於頂部和底部邊緣剛纔說的迭代器是相反的:

// get top edge 
for(x = 0; x < w; x++) { 
    for(y = 0; y < h; y++) { 
     if (buffer32[x + y * w] > 0) { 
      if (y < y1) y1 = y; 
     } 
    } 
} 

// get bottom edge 
for(x = 0; x < w; x++) { 
    for(y = h; y >= 0; y--) { 
     if (buffer32[x + y * w] > 0) { 
      if (y > y2) y2 = y; 
     } 
    } 
} 

產生的區域則是:

ctx.strokeRect(x1, y1, x2-x1, y2-y1); 

您可以實現各種優化,但它們完全取決於場景,例如,如果您知道大概的放置位置,那麼您不必遍歷所有行/列。

你可以通過跳過x個像素來做一個蠻力猜測,當你找到一個不透明的像素時,你可以基於這個等等做出一個最大搜索區域,但這超出了範圍。

希望這會有所幫助!

+0

太棒了!非常感謝,這肯定會讓我走向正確的方向。 – Mike

+0

在您急需幫助後,我能夠將其發展到我需要的解決方案。但是,在Safari中測試後,Safari看起來無法獲取線條的座標。你的小提琴反映了相同的結果。 看來這可能與Unit32Array有關。 Unit32Array函數在Safari上似乎也非常慢。 你能夠建議一個修復,以允許Safari,Ipad等..? – Mike

+0

@MikeBarkemeyer必須是Safari的問題,如果是的話,我們只能等待Apple解決這個問題。您可以在未註冊的情況下報告此問題。解決方法是使用Uint8Array,跳過4個字節並測試Alpha通道。 – K3N