Двоичный доступ
После моего комментария о низкой производительности GetPixel
для каждого пикселя я попытался написать фрагмент, который определяет наличие прозрачных пикселей на изображении или нет (включая PNG).Вот оно.
public static bool IsImageTransparent(string fullName)
{
using (Bitmap bitmap = Bitmap.FromFile(fullName) as Bitmap)
{
bool isTransparent;
// Not sure if the following enumeration is correct. Maybe some formats do not actually allow transparency.
PixelFormat[] formatsWithAlpha = new[] { PixelFormat.Indexed, PixelFormat.Gdi, PixelFormat.Alpha, PixelFormat.PAlpha, PixelFormat.Canonical, PixelFormat.Format1bppIndexed, PixelFormat.Format4bppIndexed, PixelFormat.Format8bppIndexed, PixelFormat.Format16bppArgb1555, PixelFormat.Format32bppArgb, PixelFormat.Format32bppPArgb, PixelFormat.Format64bppArgb, PixelFormat.Format64bppPArgb };
if (formatsWithAlpha.Contains(bitmap.PixelFormat))
{
// There might be transparency.
BitmapData binaryImage = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format64bppArgb);
unsafe
{
byte* pointerToImageData = (byte*)binaryImage.Scan0;
int numberOfPixels = bitmap.Width * bitmap.Height;
isTransparent = false;
// 8 bytes = 64 bits, since our image is 64bppArgb.
for (int i = 0; i < numberOfPixels * 8; i += 8)
{
// Check the last two bytes (transparency channel). First six bytes are for R, G and B channels. (0, 32) means 100% opacity.
if (pointerToImageData[i + 6] != 0 || pointerToImageData[i + 7] != 32)
{
isTransparent = true;
break;
}
}
}
bitmap.UnlockBits(binaryImage);
}
else
{
// No transparency available for this image.
isTransparent = false;
}
return isTransparent;
}
}
Плюсы:
- Двоичный доступ, намного быстрее, чем
GetPixel
, - Не требует дополнительныхни библиотеки, ни WPF,
- Работает с любым форматом, поддерживаемым GDI +: BMP, GIF, JPEG, PNG, TIFF, Exif, WMF и EMF.
Минусы:
- Требуется
unsafe
, - Это медленнее, чем чтение файла PNG напрямую.
Палитры
Менее ручной подходбудет использовать палитры.Вероятно, могут существовать некоторые .NET Framework или сторонние библиотеки, которые позволяют вам это делать.Я попробовал следующее (используя WPF):
using (Stream imageStreamSource = new FileStream(fullName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];
return bitmapSource.Palette.Colors.Any(c => c.A != 0);
}
, но у меня не работает , поскольку bitmapSource.Palette
составляет null
большую часть времени.Кроме того, использование палитр значительно снизит производительность по сравнению с первым фрагментом, поскольку каждый цвет должен быть загружен в список цветов перед продолжением.