Есть ли способ узнать о прозрачности изображения png, прочитав заголовок изображения? - PullRequest
2 голосов
/ 23 сентября 2010

Есть ли способ узнать о прозрачности изображения png, прочитав заголовок изображения?

Ответы [ 5 ]

3 голосов
/ 23 сентября 2010

Двоичный доступ

После моего комментария о низкой производительности 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 большую часть времени.Кроме того, использование палитр значительно снизит производительность по сравнению с первым фрагментом, поскольку каждый цвет должен быть загружен в список цветов перед продолжением.

1 голос
/ 23 сентября 2010

Если png проиндексирован, вы можете проверить блок TRNS Описание блоков png .Если нет, то вам нужно получить его попиксельно, как в этом методе.

1 голос
/ 23 сентября 2010

Иногда вы можете сказать, что у него определенно нет прозрачности, если битовая глубина равна 24 или если она меньше, и ни один из членов палитры не содержит соответствующего альфа-значения (вы не говорите, хотите ли вы считать частичную прозрачность как прозрачный или нет).

Однако, чтобы быть уверенным в том, что на самом деле есть некоторая прозрачность, требуется один, чтобы изучить все изображение. Следовательно, это O (n) для размера потока (который приблизительно равен O (x * y) для размера изображения), но с возможным сокращением от заголовка в некоторых случаях.

1 голос
/ 23 сентября 2010

Узнай что? Если изображение имеет прозрачность? Вы можете проверить битовую глубину, 24 бит (RGB) обычно означает, что прозрачности нет, а 32 бит (RGBA) означает слой непрозрачности / прозрачности

0 голосов
/ 23 сентября 2010

Спасибо всем.Получил это, используя ссылку ChrisF Определите, используется ли альфа-канал в изображении Спасибо ChrisF.

Вот мой код:

    private bool IsImageTransparent(Bitmap image)
    {
        for (int i = 0; i < image.Width; i++)
            for (int j = 0; j < image.Height; j++)
        {
            var pixel = image.GetPixel(i, j);
            if (pixel.A != 255)
                return true;
        } 
        return false;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...