Search code examples
c#-4.0bitmapunsafebitmapdata

unsafe code explanation


        private static Complex[,] FromBitmapData(BitmapData _BitmapData)
        {
            if (_BitmapData.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                throw new Exception("Source can be grayscale (8bpp indexed) only.");
            }

            int width = _BitmapData.Width;
            int height = _BitmapData.Height;
            int offset = _BitmapData.Stride - width;

            if ((!Utils.IsPowerOf2(width)) || (!Utils.IsPowerOf2(height)))
            {
                throw new Exception("Image width and height should be power of 2.");
            }

            Complex[,] data = new Complex[width, height];

            unsafe
            {
                byte* src = (byte*)_BitmapData.Scan0.ToPointer();

                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++, src++)
                    {
                        data[y, x] = new Complex((float)*src / 255, 
                                                    data[y, x].Imaginary);
                    }

                    src += offset;
                }
            }

            return data;
        }

Why is the value pointed by *src is divided by 255?


Solution

  • What is Stride?

    For purposes like alignment, etc. sometimes row of pixels in a bitmap is longer than width - and it’s length is called stride. So, you could have width = 3 and stride = 4, and row of data would look like this:

    Row: [Pixel][Pixel][Pixel][Unused]
    

    What does offset represent?

    It’s a difference between stride and width, i.e. when you have read all real pixels in a row, how much unused ones you need to skip in order to get to next row.

    Why is src incremented by 1 in the inner loop, and, again incremented by offset in the outer loop?

    Inner loop reads pixels of the row, so src is incremented by 1 to get to next pixel in every iteration. But after you read them all, you need to skip offset of unused data to get to next row.

    Why is the value pointed by *src is divided by 255?

    Complex type has floating point components, and pixels in 8bpp bitmaps are represented by bytes, so they have values from 0–255. Dividing by 255 converts them to floating point numbers in range 0.0–1.0.

    Why is data[x,y].Imaginary passed as a parameter?

    For some reason, this function stores bitmap data in complex type, and complex type has real and imaginary components, so assigning

    data[y, x] = new Complex(something, data[y,x].Imaginary); 
    

    means: set real component of data[y,x] to something and leave imaginary component as it is.