Question

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.)

Was it helpful?

Solution

This is a complete example with both methods, using LockBits() and GetPixel(). Besides the trust issues with LockBits() things can easily get hairy.

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
                    int position = (y * bmpData.Stride) + (x * Image.GetPixelFormatSize(bmpData.PixelFormat)/8); 
                    blue = rgbValues[position];
                    green = rgbValues[position + 1];
                    red = rgbValues[position + 2];
                    Console.WriteLine("Fast: " + red + " " 
                                       + green + " " + blue);
                }
            }
            bmp.UnlockBits(bmpData);
        }
    }
}

OTHER TIPS

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.

If your gif isn't animated use this:

Image img = Image.FromFile("image.gif");

for (int x = 0; x < img.Width; x++)
{
    for (int y = 0; y < img.Height; y++)
    {
        // Do stuff here
    }
}

(Untested)


Otherwise use this to loop through all the frames, as well:

Image img = Image.FromFile("animation.gif");

FrameDimension frameDimension = new FrameDimension(img.FrameDimensionsList[0]);
int frames = img.GetFrameCount(frameDimension);

for (int f = 0; f < frames; f++)
{
    img.SelectActiveFrame(frameDimension, f);

    for (int x = 0; x < img.Width; x++)
    {
        for (int y = 0; y < img.Height; y++)
        {
            // Do stuff here
        }
    }
}

(Untested)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top