Как определить, есть ли у растрового изображения альфа-канал в .NET - PullRequest
0 голосов
/ 15 февраля 2012

Кто-то может порекомендовать лучший способ определить, есть ли у растрового изображения альфа-канал и используется ли он?Этот метод работает для меня, но может быть неэффективным, если изображение очень большое, потому что в худшем случае оно повторяет все пиксели:

private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
{
    Rectangle bmpBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);

    bmpData = bmp.LockBits(bmpBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);

    try
    {
        for (int y = 0; y <= bmpData.Height - 1; y++)
        {
            for (int x = 0; x <= bmpData.Width - 1; x++)
            {
                Color pixelColor = Color.FromArgb(
                    Marshal.ReadInt32(
                       bmpData.Scan0, (bmpData.Stride * y) + (4 * x)));

                if (pixelColor.A > 0 & pixelColor.A < 255)
                {
                    return true;
                }
            }
        }
    }
    finally
    {
        bmp.UnlockBits(bmpData);
    }

    return false;
}
  1. Это способ продолжить илиЕсть ли оптимальное решение?
  2. Достаточно ли быстро это решение для очень больших файлов?

Большое спасибо

Ответы [ 3 ]

2 голосов
/ 23 апреля 2014

Вы не найдете решения лучше этого, мне потребовались часы, чтобы оптимизировать:

public bool IsAlphaBitmap(ref System.Drawing.Imaging.BitmapData BmpData)
{
    byte[] Bytes = new byte[BmpData.Height * BmpData.Stride];
    Marshal.Copy(BmpData.Scan0, Bytes, 0, Bytes.Length);
    for (p = 3; p < Bytes.Length; p += 4) {
        if (Bytes[p] != 255) return true;
    }
    return false;
}
1 голос
/ 15 февраля 2012

Вот пример, основанный на вашем.

private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
{
    var bmpBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
    bmpData = bmp.LockBits(bmpBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);

    try
    {
        var rowDataLength = bmpData.Width * 4;  // for 32ARGB bitmap
        var buffer = new byte[rowDataLength];

        for (var y = 0; y < bmpData.Height; y++)
        {
            Marshal.Copy((IntPtr) ((int)bmpData.Scan0 + bmpData.Stride*y), buffer, 0, rowDataLength);

            for (int p = 0; p < rowDataLength; p += 4)
            {
                if (buffer[p] > 0 && buffer[p] < 255)
                    return true;
            }
        }
    }
    finally
    {
        bmp.UnlockBits(bmpData);
    }

    return false;
}
1 голос
/ 15 февраля 2012

Не пробовал, но идея в том, чтобы работать с указателями:

unsafe
{
   byte* ptrAlpha = ((byte*)bmpData.Scan0.ToPointer()) + 3;
   for (int i = bmpData.Width * bmpData.Height; i > 0; --i)  // prefix-- should be faster
   {
      if ( *ptrAlpha < 255 )
          return true;

      ptrAlpha += 4;
   }
}
...