C# Bitmap與BitmapData理解
阿新 • • 發佈:2018-12-18
使用lockbits方法處理影象
許多影象處理任務即時是最簡單的檔案型別轉換,例如從32位深度到8位深度的格式轉化,直接獲得畫素陣列要比使用GetPixel和SetPixel等方法的效率高得多。
你可能會發現DotNet採用託管機制,大多數情況下微軟會推薦你使用託管程式碼,理由是便捷和安全。實際應用中,直接操作記憶體中的資料塊是很少見的,儘管如此,影象處理恰恰是這類為數不多的情況之一,因為使用託管程式碼的效率低的難以忍受,特別是對巨幅影象來說,在此,我們討論一下一種新的方法。
如何使用非託管程式碼是因語言而異的,在C#中我們可以通過unsafe關鍵字來呼叫指標,從而直接操作記憶體中的點陣圖資料;VB則使用Marshal類中的方法,它會導致一部分的效能損失,因此效率不如前者。
鎖定位元流
Bitmap類使用LockBits和UnLockBits方法來將點陣圖的資料矩陣儲存在記憶體中、直接對它進行操作,最後用修改後的資料代替點陣圖中的原始資料。LockBits返回以各BitmapData的類用已描述資料在已鎖定的矩陣中的位置和分佈。
BitmapData類包括以下幾個重要的屬性:
- Scan0:資料矩陣在記憶體中的地址。
- Stride:資料矩陣中的行寬,以byte為單位。可能會擴充套件幾個Byte,後面會介紹。
- PixelFormat:畫素格式,這對矩陣中位元組的定位很重要。
- Width:點陣圖的寬度。
- Height:點陣圖的高度。 具體關係見下圖:
如上圖所示,stride屬性表示點陣圖資料矩陣的行寬
for(int y=0; y<bmd.Height; y++)
{
byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
for(int x=0; x<bmd.Width; x++)
{
row[x*PixelSize]=255;
}
}
處理4位索引圖,高低位應分開處理,程式碼如下:
int offset = (y * bmd.Stride) + (x >> 1);
byte currentByte = ((byte *)bmd.Scan0)[offset];
if((x&1) == 1)
{
currentByte &= 0xF0;
currentByte |= (byte)(colorIndex & 0x0F);
}
else
{
currentByte &= 0x0F;
currentByte |= (byte)(colorIndex << 4);
}
((byte *)bmd.Scan0)[offset]=currentByte;
處理1位索引的程式碼:
byte* p=(byte*)bmd.Scan0.ToPointer();
int index=y*bmd.Stride+(x>>3);
byte mask=(byte)(0x80>>(x&0x7));
if(pixel)
p[index]|=mask;
else
p[index]&=(byte)(mask^0xff);
最後在進行完所有處理後馬不要忘記使用Unlockbits命令解鎖。