簡體   English   中英

有沒有一種方法可以通過讀取圖像標題來了解png圖像的透明度?

[英]Is there a way to find out about a png image transparency by reading the image header?

有沒有一種方法可以通過讀取圖像標題來了解png圖像的透明度?

二進制訪問

在對每個像素的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.Palettenull的。 此外,與第一個片段相比,使用調色板會嚴重降低性能,因為在繼續操作之前必須將每種顏色加載到顏色列表中。

找出什么? 圖像是否透明? 您可以檢查位深度,24位(RGB)通常表示沒有透明度,而32位(RGBA)則表示存在不透明/透明層

有時,您可以告訴您,如果位深度為24或更低,並且所有調色板成員均不包含相關的Alpha值,則絕對不具有透明度(您不必說是否要將部分透明度計為透明或不透明。不)。

但是,要確保實際上有一定的透明度,確實需要檢查整個圖像。 因此,對於流大小,它為O(n)(對於圖像大小,它大約為O(x * y)),但在某些情況下,標頭可能會出現捷徑。

如果為png編制了索引,則可以檢查TRNS塊Png塊描述 如果不是,則需要像在該方法中那樣逐個獲取它。

感謝大家。 通過使用ChrisF的鏈接使它正常工作感謝ChrisF, 確定圖像中是否使用了Alpha通道

這是我的代碼:

    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;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM