views:

383

answers:

2

I need to step through a .gif image and determine the RGB value of each pixel, x and y coordinates. Can someone give me an overview of how I can accomplish this? (methodology, which namespaces to use, etc.)

+8  A: 

Here goes a complete example with both methods, using LockBits() and GetPixel(). Besides the trust issues with LockBits() things can easily get hairy. A great explanation about the issues involved (Stride, Format, Padding and so on) is located here.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace BitmapReader
{
    class Program
    {
        static void Main(string[] args)
        {
            //Try a small pic to be able to compare output, 
            //a big one to compare performance
            System.Drawing.Bitmap b = new 
                System.Drawing.Bitmap(@"C:\Users\vinko\Pictures\Dibujo2.jpg"); 
            doSomethingWithBitmapSlow(b);
            doSomethingWithBitmapFast(b);
        }

        public static void doSomethingWithBitmapSlow(System.Drawing.Bitmap bmp)
        {

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    Color clr = bmp.GetPixel(x, y);

                    int red = clr.R;
                    int green = clr.G;
                    int blue = clr.B;
                    Console.WriteLine("Slow: " + red + " " 
                                       + green + " " + blue);
                }
            }
        }

        public static void doSomethingWithBitmapFast(System.Drawing.Bitmap bmp)
        {
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, 
                    System.Drawing.Imaging.ImageLockMode.ReadOnly,
                    bmp.PixelFormat);

            IntPtr ptr = bmpData.Scan0;

            int bytes = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[bytes];

            System.Runtime.InteropServices.Marshal.Copy(ptr, 
                           rgbValues, 0, bytes);

            byte red = 0;
            byte green = 0;
            byte blue = 0;

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    //See the link above for an explanation 
                    //of this calculation (assumes 24bppRgb format)
                    int position = (y * bmpData.Stride) + (x * 3); 
                    blue = rgbValues[position];
                    green = rgbValues[position + 1];
                    red = rgbValues[position + 2];
                    Console.WriteLine("Fast: " + red + " " 
                                       + green + " " + blue);
                }
            }
            bmp.UnlockBits(bmpData);
        }
    }
}
Vinko Vrsalovic
I have never been able to implement any type of image processing using Get/SetPixel. It is always *way* too slow, even for trivial operations like increases overall brightness.
Ed Swangren
It's always too slow when your images are big. For icon sized images it's perfectly suitable :-)
Vinko Vrsalovic
Oh, well, yeah :-)
Ed Swangren
+7  A: 

You can load the image using new Bitmap(filename) and then use Bitmap.GetPixel repeatedly. This is very slow but simple. (See Vinko's answer for an example.)

If performance is important, you might want to use Bitmap.LockBits and unsafe code. Obviously this reduces the number of places you'd be able to use the solution (in terms of trust levels) and is generally more complex - but it can be a lot faster.

Jon Skeet
Jon, don't you ever sleep ? ;)
Thomas Levesque
Wow. I was looking for this a few weeks ago. Definitely will look more into the example. Thank you for the link.
maxwellb
It is quite a lot more complex (and quite a lot faster indeed), you have to take into consideration the PixelFormat of the image, check if the data is or is not padded and skip some values accordingly. The MSDN example is not particularly helpful as it doesn't mention any of this.
Vinko Vrsalovic