有没有办法通过读取图像标题找出png图像透明度?

时间:2010-09-23 14:21:12

标签: c# .net png

有没有办法通过阅读图片标题来了解png图像的透明度?

5 个答案:

答案 0 :(得分:2)

二进制访问

根据我对每个像素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 :(得分:1)

找出什么?如果图像透明度?您可以检查位深度,24位(RGB)通常表示没有透明度,32位(RGBA)表示存在不透明度/透明度层

答案 2 :(得分:1)

如果png已编入索引,则可以检查TRNS块Png chunks description。如果没有,那么你需要像在那个方法中一样逐个像素地获取它。

答案 3 :(得分:0)

如果位深度为24或者更低且没有任何调色板成员包含相关的alpha值,您有时可以确定它肯定没有透明度(您没有说明是否要计算部分透明度)透明与否)。

但是,为了确保实际存在一些透明度,确实需要检查整个图像。因此,对于流大小来说它是O(n)(对于图像大小大致为O(x * y)),但在某些情况下可能会从标题中略微缩短。

答案 4 :(得分:0)

谢谢大家。通过使用ChrisF的链接来实现它 Determine if Alpha Channel is Used in an Image 谢谢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;
    }