Sunday, June 7, 2020

CSharp - Getting the proper number of bits used in a image or bits per pixel or bits per channel

Gets the colloquial "Bit Depth" of an image, but technically gets the bits per channel.
This sample solution illustrates the shortcomings of standard windows image library and uses a third party SharpDX lib to get image pixel format, and thus the "bit depth" of an image. It seems to be the only library that works consistently, in regards to getting the correct info for an image. 

System.Windows.Media and System.Drawing report different pixel formats for same image and incorrectly for 16-bit images in particular.

This is
custom solution is provided for bits per pixel for an image which is really report bits per channel, but commonly misinterpreted. See below.

Test Suite

http://www.schaik.com/pngsuite/pngsuite_bas_png.html













Motivation

There is a great deal of confusion, for the general public regarding the expectation what bit depth is, it loosely refers to number of bits used in an image versus number of bits used per each channel or color. When referring to a pixel, the concept can be defined as bits per pixel (bpp), which specifies the number of bits used. When referring to a color component, the concept can be defined as bits per component, bits per channel, bits per sample, bits per color (all three abbreviated bpc), and also bits per pixel component, bits per color channel or bits per sample (bps).
Refer to https://en.wikipedia.org/wiki/Color_depth for full digest.

 Download GitHub repo which includes full Visual Studio 2010 project using .NET 4.0 (for max upgrade-ability) and references to latest SharpDX lib 4.2.0

Note: This took many hours of investigation trying a number of Windows Imaging Component (WIC) libraries and image metadata tools, such as ImageMagick,  ExifTool (worked but slow), Exiv2 and slew of image metadata projects for images and lasting the ever promising Microsoft Windows API Code Pack. All failed or did not provide this information consistently for every image.

        /// Gets bits per channel strictly speaking, but is this commonly confused as bits per pixel and we'll use this expectation
        /// </summary>
        /// <param name="pixelFormat">System.Windows.Media.PixelFormat</param>
        /// <returns>int bits per channel</returns>
        /// <author> MetadataConsulting.ca</author>
        /// <created>Sun 07-Jun-20 1:27am</created>
        //  https://en.wikipedia.org/wiki/Color_depth
        //  get from source - https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Media/PixelFormat.cs
        //License - https://www.gnu.org/licenses/gpl-3.0.html        
        public int GetBitsPerPixelakaChannel(System.Windows.Media.PixelFormat pixelFormat)
        {
            
            //var x = (System.Windows.Media.PixelFormat)pixelformat;  //no conversion available

            string strPF = pixelFormat.ToString(); 

            switch (strPF)
            {
                case "Default": 
                    return -1; //Gets the pixel format that is best suited for the particular operation or here not found!

                case "Indexed1":
                    return 1; //Gets the pixel format specifying a paletted bitmap with 2 colors.

                case "Indexed2":
                    return 2; //Gets the pixel format specifying a paletted bitmap with 4 colors.

                case "Indexed4":
                    return 4; //Gets the pixel format specifying a paletted bitmap with 16 colors.

                case "Indexed8":
                    return 8; //Gets the pixel format specifying a paletted bitmap with 256 colors.

                case "BlackWhite":
                    return 1; //Gets the black and white pixel format which displays one bit of data per pixel as either black or white.

                case "Gray2":
                    return 2; //Gets the Gray2 pixel format which displays a 2 bits-per-pixel grayscale channel, allowing 4 shades of gray.

                case "Gray4":
                    return 4; //Gets the Gray4 pixel format which displays a 4 bits-per-pixel grayscale channel, allowing 16 shades of gray.

                case "Gray8":
                    return 8; //Gets the Gray8 pixel format which displays an 8 bits-per-pixel grayscale channel, allowing 256 shades of gray.

                case "Gray16":
                    return 16; //Gets the Gray16 pixel format which displays a 16 bits-per-pixel grayscale channel, allowing 65536 shades of gray. This format has a gamma of 1.0.

                case "Gray32Float":
                    return 32; //Gets the Gray32Float pixel format. Gray32Float displays a 32 bits per pixel (BPP) grayscale channel, allowing over 4 billion shades of gray. This format has a gamma of 1.0.

                case "Bgr555":
                    return 5; //Gets the Bgr555 pixel format. Bgr555 is a sRGB format with 16 bits per pixel (BPP). Each color channel (blue, green, and red) is allocated 5 bits per pixel (BPP).

                case "Bgr565"://Note: Hard to choose a good value here, unless we return a decimal perhaps 5.65 then
                    return 6; //Gets the Bgr565 pixel format. Bgr565 is a sRGB format with 16 bits per pixel(BPP).Each color channel(blue, green, and red) is allocated 5, 6, and 5 bits per pixel(BPP) respectively.

                case "Bgr101010":
                    return 10; //Gets the Bgr101010 pixel format. Bgr101010 is a sRGB format with 32 bits per pixel (BPP). Each color channel (blue, green, and red) is allocated 10 bits per pixel (BPP).

                case "Bgr24":
                    return 8; //Gets the Bgr24 pixel format. Bgr24 is a sRGB format with 24 bits per pixel (BPP). Each color channel (blue, green, and red) is allocated 8 bits per pixel (BPP).

                case "Rgb24":
                    return 8; //Gets the Rgb24 pixel format. Rgb24 is a sRGB format with 24 bits per pixel (BPP). Each color channel (red, green, and blue) is allocated 8 bits per pixel (BPP).

                case "Bgr32":
                    return 8; //Gets the Bgr32 pixel format. Bgr32 is a sRGB format with 32 bits per pixel (BPP). Each color channel (blue, green, and red) is allocated 8 bits per pixel (BPP).

                case "Bgra32":
                    return 8; //Gets the Bgra32 pixel format. Bgra32 is a sRGB format with 32 bits per pixel (BPP). Each channel (blue, green, red, and alpha) is allocated 8 bits per pixel (BPP).

                case "Pbgra32":
                    return 8; //Gets the Pbgra32 pixel format. Pbgra32 is a sRGB format with 32 bits per pixel (BPP). Each channel (blue, green, red, and alpha) is allocated 8 bits per pixel (BPP). Each color channel is pre-multiplied by the alpha value.

                case "Rgb48":
                    return 16; //Gets the Rgb48 pixel format. Rgb48 is a sRGB format with 48 bits per pixel (BPP). Each color channel (red, green, and blue) is allocated 16 bits per pixel (BPP). This format has a gamma of 1.0.

                case "Rgba64":
                    return 16; //Gets the Rgba64 pixel format. Rgba64 is an sRGB format with 64 bits per pixel (BPP). Each channel (red, green, blue, and alpha) is allocated 16 bits per pixel (BPP). This format has a gamma of 1.0.

                case "Prgba64":
                    return 32; //Gets the Prgba64 pixel format. Prgba64 is a sRGB format with 64 bits per pixel (BPP). Each channel (blue, green, red, and alpha) is allocated 32 bits per pixel (BPP). Each color channel is pre-multiplied by the alpha value. This format has a gamma of 1.0.

        
                case "Rgb128Float":
                    return 32; //Gets the Rgb128Float pixel format. Rgb128Float is a ScRGB format with 128 bits per pixel (BPP). Each color channel is allocated 32 BPP. This format has a gamma of 1.0.

                case "Rgba128Float":
                    return 32; //Gets the Rgba128Float pixel format. Rgba128Float is a ScRGB format with 128 bits per pixel (BPP). Each color channel is allocated 32 bits per pixel (BPP). This format has a gamma of 1.0.

                case "Prgba128Float":
                    return 32; //Gets the Prgba128Float pixel format. Prgba128Float is a ScRGB format with 128 bits per pixel (BPP). Each channel (red, green, blue, and alpha) is allocated 32 bits per pixel (BPP). Each color channel is pre-multiplied by the alpha value. This format has a gamma of 1.0.

                case "Cmyk32":
                    return 8; //Gets the Cmyk32 pixel format which displays 32 bits per pixel (BPP) with each color channel (cyan, magenta, yellow, and black) allocated 8 bits per pixel (BPP).
            }

            return -1; 
        }

No comments:

Post a Comment