thecodekid thecodekid - 3 months ago 24
C# Question

Getting RGB array from image in C#

I'm currently writing an C# implementation of a little program which i have written in Java.
I had used

BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
function in my java app.But i couldn't exactly find a version of this in C# and i'm not sure how to write it manually.Need a hand.

Answer

There's not a direct equivalent in the .NET Framework to this method. However, if your image is a System.Drawing.Bitmap, you can call the LockBits method, and this will return a BitmapData structure that contains the address of the first scanline. You can then use it to create what should be an API-compatible wrapper. I'm assuming you're using C# 3.5 or greater, so I'm using an extension method - if you're using an older flavor, change this to a regular method by dropping the 'this' from the Bitmap argument:

    public static void getRGB(this Bitmap image, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
    {
        const int PixelWidth = 3;
        const PixelFormat PixelFormat = PixelFormat.Format24bppRgb;

        // En garde!
        if (image == null) throw new ArgumentNullException("image");
        if (rgbArray == null) throw new ArgumentNullException("rgbArray");
        if (startX < 0 || startX + w > image.Width) throw new ArgumentOutOfRangeException("startX");
        if (startY < 0 || startY + h > image.Height) throw new ArgumentOutOfRangeException("startY");
        if (w < 0 || w > scansize || w > image.Width) throw new ArgumentOutOfRangeException("w");
        if (h < 0 || (rgbArray.Length < offset + h * scansize) || h > image.Height) throw new ArgumentOutOfRangeException("h");

        BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat);
        try
        {
            byte[] pixelData = new Byte[data.Stride];
            for (int scanline = 0; scanline < data.Height; scanline++)
            {
                Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride);
                for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++)
                {
                    // PixelFormat.Format32bppRgb means the data is stored
                    // in memory as BGR. We want RGB, so we must do some 
                    // bit-shuffling.
                    rgbArray[offset + (scanline * scansize) + pixeloffset] = 
                        (pixelData[pixeloffset * PixelWidth + 2] << 16) +   // R 
                        (pixelData[pixeloffset * PixelWidth + 1] << 8) +    // G
                        pixelData[pixeloffset * PixelWidth];                // B
                }
            }
        }
        finally
        {
            image.UnlockBits(data);
        }
    }

This wrapper can now be called like this:

        Bitmap foo = Bitmap.FromFile(@"somefile.jpg") as Bitmap;
        int[] rgbArray = new int[100];
        foo.getRGB(1, 1, 10, 10, rgbArray, 0, 10);

Hope this helps, and welcome to .NET!

Comments