Check If Image Is Colored Or Not

时光毁灭记忆、已成空白 提交于 2019-12-05 13:04:28

You can improve this by avoiding Color.FromArgb, and iterating over bytes instead of ints, but I thought this would be more readable for you, and easier to understand as an approach.

The general idea is draw the image into a bitmap of known format (32bpp ARGB), and then check whether that bitmap contains any colors.

Locking the bitmap's bits allows you to iterate through it's color-data many times faster than using GetPixel, using unsafe code.

If a pixel's alpha is 0, then it is obviously GrayScale, because alpha 0 means it's completely opaque. Other than that - if R = G = B, then it is gray (and if they = 255, it is black).

private static unsafe bool IsGrayScale(Image image)
{
    using (var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
    {
        using (var g = Graphics.FromImage(bmp))
        {
            g.DrawImage(image, 0, 0);
        }

        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

        var pt = (int*)data.Scan0;
        var res = true;

        for (var i = 0; i < data.Height * data.Width; i++)
        {
            var color = Color.FromArgb(pt[i]);

            if (color.A != 0 && (color.R != color.G || color.G != color.B))
            {
                res = false;
                break;
            }
        }

        bmp.UnlockBits(data);

        return res;
    }
}
    private bool isGrayScale(Bitmap processedBitmap)
    { 
        bool res = true;
        unsafe
        {
            System.Drawing.Imaging.BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
            int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
            int heightInPixels = bitmapData.Height;
            int widthInBytes = bitmapData.Width * bytesPerPixel;
            byte* PtrFirstPixel = (byte*)bitmapData.Scan0;
            Parallel.For(0, heightInPixels, y =>
            {
                byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
                for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
                {
                    int b = currentLine[x];
                    int g = currentLine[x + 1];
                    int r = currentLine[x + 2];
                    if (b != g || r != g)
                    {
                        res = false;
                        break;
                    }
                }
            });
            processedBitmap.UnlockBits(bitmapData);
        }
        return res;
    }

SimpleVar's answer is mostly correct: that code doesn't properly handle when the source image has an indexed color format.

To solve this, simply replace the outer using block with:

using (var bmp = new Bitmap(image)) {

and remove the inner using entirely, as the Graphics object is no longer needed. This will create a perfect copy of the image in a non-indexed format, regardless of the original image's pixel format.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!