Альфа-маскировка в c # System.Drawing? - PullRequest
17 голосов
/ 07 сентября 2010

Я пытаюсь нарисовать изображение с источником Bitmap и альфа-маской Bitmap, используя объект System.Drawing.Graphics.В настоящий момент я зацикливаю X и Y и использую GetPixel и SetPixel, чтобы записать исходный цвет и маску альфа в третью Bitmap, а затем отрендерить это.Однако это очень неэффективно, и мне интересно, есть ли более быстрый способ добиться этого?

Эффект, который я ищу, выглядит следующим образом:

Effect I’m after

Сетка представляет прозрачность;Вы, наверное, знали это.

Ответы [ 2 ]

15 голосов
/ 07 сентября 2010

Да, более быстрый способ сделать это - использовать Bitmap.LockBits и использовать арифметику указателя для получения значений вместо GetPixel и SetPixel. Недостатком, конечно, является то, что вы должны использовать небезопасный код; если вы допустите ошибку, вы можете вызвать действительно серьезные сбои в вашей программе. Но если вы держите его простым и автономным, все будет хорошо (эй, если я смогу, вы тоже можете это сделать).

Например, вы можете сделать что-то вроде этого (не проверено, используйте на свой страх и риск):

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

В этом примере выводится альфа-канал на выходе из синего канала в изображении маски. Я уверен, что вы можете изменить его, чтобы при необходимости использовать красный или альфа-канал маски.

5 голосов
/ 29 сентября 2011

В зависимости от ваших требований это может быть намного проще:

  • Инвертируйте вашу маску так, чтобы круг был прозрачным, а остальное от цвета, не используемого в вашем входном растровом изображении (как красный в вашем примере)
  • Нарисуйте маску поверх изображения, используя Graphics.FromImage (image) .DrawImage (mask) ...
  • Установите цвет маски прозрачным на вашем изображении (image.MakeTransparent (Color.Red))

Единственный недостаток этого метода заключается в том, что вам необходимо убедиться, что цвет маски не используется в вашем изображении.Я не знаю, медленнее ли это или быстрее, чем ручным способом.

...