2010-09-06 25 views
17

ve Bitmap kaynak kodlu bir görüntüyü System.Drawing.Graphics nesnesini kullanarak çizmeye çalışıyorum. Şu anda X ve Y döngülerinde GetPixel ve SetPixel ve SetPixel kaynak kodlarını ve alfa maskesini üçüncü bir Bitmap'a yazıp kullanın. Ancak bu çok verimsiz ve bunu başarmanın daha hızlı bir yolu olup olmadığını merak ediyorum?Alfa maskeleme C# System.Drawing?

böyle görünüyor peşindeyim etkisi:

Effect I’m after

ızgara deseni şeffaflığı temsil eder; Muhtemelen bunu biliyordun.

+2

System.Drawing.Graphics'i kullandığınızı söylediğinizden, bu muhtemelen konu dışıdır, ancak WPF'de donanım ivmelenmesinden faydalanan opaklık maskelerinin bir bağlantısı: http://msdn.microsoft.com/ en-us/library/system.windows.media.drawinggroup.opacitymask.aspx – Douglas

+0

konu dışı, ama yine de büyüleyici - teşekkürler! – Origamiguy

cevap

15

Evet, bunu yapmanın daha hızlı yolu Bitmap.LockBits kullanmak ve GetPixel ve SetPixel yerine değerleri almak için işaretçi aritmetiğini kullanmaktır. Dezavantajı, elbette, güvenli olmayan kod kullanmanız gerektiğidir; Eğer bir hata yaparsanız, programınızda gerçekten kötü kazalara neden olabilirsiniz. Ama bunu basit ve müstakil bir yerde tutarsanız, iyi olmalıdır (hey, yapabilirsem, bunu da yapabilirsiniz).

Örneğin, (kendi sorumluluğunuzdadır test edilmedi, kullanımı) böyle bir şey yapabileceğini:

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(...); 

Bu örnek maske görüntüde mavi kanaldan çıkışında alfa kanalını türetir . Gerektiğinde maskenin kırmızı veya alfa kanalını kullanmak için değiştirebileceğinizi eminim.

+0

Yine de pikselleri yinelemeliyim, değil mi? – Origamiguy

+0

Evet, ancak çok hızlı. Potansiyel olarak kullanabileceğiniz başka herhangi bir uygulama, eşit olarak pikseller boyunca yinelemek zorunda kalacaktır. – Timwi

+0

Peki, işe yarıyor ve kesinlikle önceki yöntemden daha hızlı, teşekkürler! – Origamiguy

3

İhtiyaca göre bu çok daha kolay olabilir: çember saydamdır ve dinlenme (sizin örnekte kırmızı gibi) giriş Bitmapteki kullanılmaz bir renkten böylece

  • maskeni ters çevir
  • kullanarak görüntünün üst kısmında maskeni çizin Graphics.FromImage (image) .DrawImage (maske) ... senin resmin üzerine şeffaf maske rengini ayarlayın
  • (image.MakeTransparent (Color.Red))

Bu yöntemin tek dezavantajı, görüntünüzde maske renginin kullanılmadığından emin olmanızın gerekmesidir. Bunun, manuel yoldan daha yavaş mı yoksa hızlı mı olduğunu bilmiyorum.

İlgili konular