14

プログラムに画像を取り込んでいるときに、次のことを確認したいと思います。

  1. 彼らはアルファチャンネルを持っています
  2. そのアルファチャンネルが使用されている場合

#1は、を使用するだけで十分簡単Image.IsAlphaPixelFormatです。ただし、 #2については、すべての単一ピクセルをループする以外に、少なくとも1つのピクセルに使用されているアルファチャンネルがあるかどうかを判断できる簡単な方法があります(つまり、 以外の値に設定されています255)?必要なのはブール値だけです。それから、32 ビットまたは 24 ビットのどちらに保存するかを決定します。

更新: ImageFlags.HasTranslucentが探しているものを提供する必要があることを発見しました-残念ながら、まったく機能しません。たとえば、少なくとも 66 のアルファ チャネル (半透明) を持つピクセル形式の PNG は引き続き報告されますFalse(使用法: if((img.Flags & ImageFlags.HasTranslucent) == 4) ...;)。アルファ値が 0 より大きく 255 より小さい .bmp を含むすべてのタイプの画像でテストしましたが、それでもFalse. これを使ったことがあり、GDI+ でも動作するかどうか知っている人はいますか?

4

7 に答える 7

8

すべてのピクセルをループする必要はありません (そうかもしれませんが、画像によって異なります)。すべてのピクセルをループするように設定しますが、255 以外のアルファ値が見つかった場合は、次の疑似コードを使用してループから抜け出します。

bool hasAlpha = false;
foreach (var pixel in image)
{
    hasAlpha = pixel.Alpha != 255;
    if (hasAlpha)
    {
        break;
    }
}

アルファを持たない画像のすべてのピクセルをチェックするだけで済みます。アルファを持つ画像の場合、これはすぐに発生します。

于 2010-06-17T19:29:33.877 に答える
7

さまざまな種類の画像に対して一連のメソッドを組み合わせることで、この最終的な方法が得られました。これは、透過する可能性のある gif やアルファ チャネルを含む png など、ダンプする画像に対して適切に機能するようです。高速バイト読み取り方法に対する Elmo の回答に感謝します。

補足:使用しないImage.IsAlphaPixelFormat(bitmap.PixelFormat))でください:インデックス付き (パレット) 形式はアルファ非対応と見なされますが、そのような画像実際にはアルファを持つことができます。ピクセルごとではなく、パレット エントリごとです。ただし、このようなアルファ対応の 8 ビット イメージでは、HasAlpha フラグが有効になっているため、これは依然として有用なチェックです。

[[注: それ以来、私はこのロジックを大幅に単純化しました。私の他の答えを見てください。]]

public static Boolean HasTransparency(Bitmap bitmap)
{
    // not an alpha-capable color format.
    if ((bitmap.Flags & (Int32)ImageFlags.HasAlpha) == 0)
        return false;
    // Indexed formats. Special case because one index on their palette is configured as THE transparent color.
    if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed || bitmap.PixelFormat == PixelFormat.Format4bppIndexed)
    {
        ColorPalette pal = bitmap.Palette;
        // Find the transparent index on the palette.
        Int32 transCol = -1;
        for (int i = 0; i < pal.Entries.Length; i++)
        {
            Color col = pal.Entries[i];
            if (col.A != 255)
            {
                // Color palettes should only have one index acting as transparency. Not sure if there's a better way of getting it...
                transCol = i;
                break;
            }
        }
        // none of the entries in the palette have transparency information.
        if (transCol == -1)
            return false;
        // Check pixels for existence of the transparent index.
        Int32 colDepth = Image.GetPixelFormatSize(bitmap.PixelFormat);
        BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        Int32 stride = data.Stride;
        Byte[] bytes = new Byte[bitmap.Height * stride];
        Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
        bitmap.UnlockBits(data);
        if (colDepth == 8)
        {
            // Last line index.
            Int32 lineMax = bitmap.Width - 1;
            for (Int32 i = 0; i < bytes.Length; i++)
            {
                // Last position to process.
                Int32 linepos = i % stride;
                // Passed last image byte of the line. Abort and go on with loop.
                if (linepos > lineMax)
                    continue;
                Byte b = bytes[i];
                if (b == transCol)
                    return true;
            }
        }
        else if (colDepth == 4)
        {
            // line size in bytes. 1-indexed for the moment.
            Int32 lineMax = bitmap.Width / 2;
            // Check if end of line ends on half a byte.
            Boolean halfByte = bitmap.Width % 2 != 0;
            // If it ends on half a byte, one more needs to be processed.
            // We subtract in the other case instead, to make it 0-indexed right away.
            if (!halfByte)
                lineMax--;
            for (Int32 i = 0; i < bytes.Length; i++)
            {
                // Last position to process.
                Int32 linepos = i % stride;
                // Passed last image byte of the line. Abort and go on with loop.
                if (linepos > lineMax)
                    continue;
                Byte b = bytes[i];
                if ((b & 0x0F) == transCol)
                    return true;
                if (halfByte && linepos == lineMax) // reached last byte of the line. If only half a byte to check on that, abort and go on with loop.
                    continue;
                if (((b & 0xF0) >> 4) == transCol)
                    return true;
            }
        }
        return false;
    }
    if (bitmap.PixelFormat == PixelFormat.Format32bppArgb || bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
    {
        BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        Byte[] bytes = new Byte[bitmap.Height * data.Stride];
        Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
        bitmap.UnlockBits(data);
        for (Int32 p = 3; p < bytes.Length; p += 4)
        {
            if (bytes[p] != 255)
                return true;
        }
        return false;
    }
    // Final "screw it all" method. This is pretty slow, but it won't ever be used, unless you
    // encounter some really esoteric types not handled above, like 16bppArgb1555 and 64bppArgb.
    for (Int32 i = 0; i < bitmap.Width; i++)
    {
        for (Int32 j = 0; j < bitmap.Height; j++)
        {
            if (bitmap.GetPixel(i, j).A != 255)
                return true;
        }
    }
    return false;
}
于 2016-08-18T08:36:45.953 に答える
6

ChrisF の回答に基づいて、より高度なソリューションを取得します。

public bool IsImageTransparent(Bitmap image,string optionalBgColorGhost)
    {
        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;
            }
        }

        //Check 4 corners to check if all of them are with the same color!
        if (!string.IsNullOrEmpty(optionalBgColorGhost))
        {
            if (image.GetPixel(0, 0).ToArgb() == GetColorFromString(optionalBgColorGhost).ToArgb())
            {
                if (image.GetPixel(image.Width - 1, 0).ToArgb() == GetColorFromString(optionalBgColorGhost).ToArgb())
                {
                    if (image.GetPixel(0, image.Height - 1).ToArgb() ==
                        GetColorFromString(optionalBgColorGhost).ToArgb())
                    {
                        if (image.GetPixel(image.Width - 1, image.Height - 1).ToArgb() ==
                            GetColorFromString(optionalBgColorGhost).ToArgb())
                        {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    public static Color GetColorFromString(string colorHex)
    {
        return ColorTranslator.FromHtml(colorHex);
    }

非透過画像へのオプションの背景色文字列があります。

使用例:

IsImageTransparent(new Bitmap(myImg),"#FFFFFF");
于 2012-10-15T11:24:52.407 に答える