2010-09-06 102 views
17

我正在嘗試使用System.Drawing.Graphics對象來繪製圖像,其中源Bitmap和alpha掩碼Bitmap。 此刻我循環X和Y,並使用GetPixelSetPixel將源顏色和遮罩alpha寫入第三個Bitmap,然後再渲染它。 但是,這是非常低效的,我想知道是否有更快的方法來實現這一目標?Alpha遮罩在c#System.Drawing?

長相後,我很喜歡這樣的效果:

Effect I’m after

網格圖案表示的透明度;你可能知道這一點。

+2

既然你說你正在使用System.Drawing.Graphics,這可能是無關緊要的,但是這裏有一個WPF中不透明蒙板的鏈接,它將利用硬件加速:http://msdn.microsoft.com/ en-us/library/system.windows.media.drawinggroup.opacitymask.aspx – Douglas 2010-09-06 21:11:27

+0

偏離主題,但令人着迷 - 謝謝! – Origamiguy 2010-09-06 21:14:08

回答

15

是的,更快的方法是使用Bitmap.LockBits並使用指針算術檢索值而不是GetPixelSetPixel。不利的一面是,你必須使用不安全的代碼;如果你犯了一個錯誤,你的程序可能會導致一些非常糟糕的崩潰。但如果你保持簡單和獨立,它應該沒問題(嘿,如果我能做到,你也可以做到)。

例如,你可以做這樣的事情(未測試,使用風險自負):

Bitmap mask = ...; 
Bitmap input = ...; 

Bitmap output = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppArgb); 
var rect = new Rectangle(0, 0, input.Width, input.Height); 
var bitsMask = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
var bitsInput = input.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
var bitsOutput = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 
unsafe 
{ 
    for (int y = 0; y < input.Height; y++) 
    { 
     byte* ptrMask = (byte*) bitsMask.Scan0 + y * bitsMask.Stride; 
     byte* ptrInput = (byte*) bitsInput.Scan0 + y * bitsInput.Stride; 
     byte* ptrOutput = (byte*) bitsOutput.Scan0 + y * bitsOutput.Stride; 
     for (int x = 0; x < input.Width; x++) 
     { 
      ptrOutput[4 * x] = ptrInput[4 * x];   // blue 
      ptrOutput[4 * x + 1] = ptrInput[4 * x + 1]; // green 
      ptrOutput[4 * x + 2] = ptrInput[4 * x + 2]; // red 
      ptrOutput[4 * x + 3] = ptrMask[4 * x];  // alpha 
     } 
    } 
} 
mask.UnlockBits(bitsMask); 
input.UnlockBits(bitsInput); 
output.UnlockBits(bitsOutput); 

output.Save(...); 

這個例子派生從藍色通道輸出Alpha通道的掩模圖像。我敢肯定,如果需要,您可以將其更改爲使用蒙版的紅色或Alpha通道。

+0

我仍然需要迭代像素,對吧? – Origamiguy 2010-09-06 20:56:19

+0

是的,但速度非常快。任何其他可能使用的實現都必須遍歷像素。 – Timwi 2010-09-06 20:57:18

+0

嗯,它的工作原理,它肯定比我以前的方法更快,謝謝! – Origamiguy 2010-09-06 22:46:05

3

根據您的要求,這可能是更容易:

  • 翻轉你的面具,以使圓形是透明的,其餘的是從顏色 在你的輸入位(在你的例子,如紅色)不使用
  • 畫上使用您的圖像的頂部你的面具 Graphics.FromImage(圖).DrawImage(面罩)...
  • 設置屏蔽顏色爲透明圖像上 (image.MakeTransparent(Color.Red))

此方法的唯一缺點是它需要您確保圖像中未使用遮罩顏色。 我不知道這是否比手動方式更慢或更快。