Faster C#



Hi everybody, my name is Roshan Khan and I’m a dev working on Windows Mobile at MS. I’ve been working at the Mobile Devices division for the past 18 months. For the majority of my day I’m working in C++  and on a few unfortunate occasions assembly. Whenever I get the chance however, I try to push managed code.   In fact, you may be surprised to know that with Windows Mobile 6.1 we are shipping a feature written entirely in managed code (guess which one!).


While pushing my vigilante managed code agenda I’ve run headfirst into the limitations of the Compact Framework. The CF team did a great job getting ~30% of the functionality into ~10% of the space. And with a little bit of work you can get around many of the obstacles presented by the reduced code! And hopefully this article shows you one or two ways I managed to do this.


Today’s lesson is fast bitmap manipulation. Trying to alter pixels on an image is an intensive operation due to the problems associated with accessing managed memory. It’s just plain slow. This won’t be a big concern if all you are doing is drawing an image to a graphics object – but when you want to run a per-pixel filter on an image you quickly hit a performance bottleneck.


For this tutorial lets create a few classes that will let us invert the pixels on an image. The first thing we need to do is create a faster bitmap class. I’m going to make a class called FastBitmap, but I can’t subclass from Bitmap since it’s sealed. Oh no! Relax … we can fix this. Let’s create a class that contains a member variable that is a bitmap.


    public class FastBitmap


    {


        private Bitmap image;


 


But with this we won’t be able to pass in our FastBitmap into methods that accept Bitmaps – this is going to be a problem. One way to solve this is to simply pass in FastBitmap.image into the places that want a Bitmap, but this is a suboptimal solution. Instead let’s use the power of implicit casting!


        public static implicit operator Image(FastBitmap bmp)


        {


            return bmp.image;


        }


 


        public static implicit operator Bitmap(FastBitmap bmp)


        {


            return bmp.image;


        }


 


With this code we can now cast a FastBitmap object to an Image or Bitmap object on the fly. This helps especially when plugging the FastBitmap class into an existing application that is already using Bitmaps.


 


But we still haven’t solved our performance problems. How do we quickly manipulate the pixels on an image? Simple – lock the pixels in memory so we can access them quickly and in a contiguous fashion. This is done via the LockBits method. I’m going to add the following methods to our FastBitmap class that allow us to put the managed pixel data into a format that is better suited for direct manipulation.


        public void LockPixels()


        {


            LockPixels(new Rectangle(0, 0, image.Width, image.Height));


        }


 


        private void LockPixels(Rectangle area)


        {


            if (locked)


                return;


            locked = true;


            bitmapData = image.LockBits(area, ImageLockMode.ReadWrite,


                PixelFormat.Format24bppRgb);


            IntPtr ptr = bitmapData.Scan0;


            int stride = bitmapData.Stride;


            int numBytes = image.Width * image.Height * 3;


            rgbValues = new byte[numBytes];


            Marshal.Copy(ptr, rgbValues, 0, numBytes);


        }


 


        public void UnlockPixels()


        {


            if (!locked)


                return;


            locked = false;


Marshal.Copy(rgbValues, 0, bitmapData.Scan0, image.Width * image.Height * 3);


            image.UnlockBits(bitmapData);


            locked = false;


        }


 


By calling lock pixels we can copy the pixel data from memory into an array that we will manipulate later on. When we call UnlockPixels we dump this entire array back into our managed image in one atomic operation.


 


I’m going to ahead a few more methods to our FastBitmap class for ease of use. Here’s the completed class.


    public class FastBitmap


    {


        private Bitmap image;


        private BitmapData bitmapData;


        private int height;


        private int width;


        private byte[] rgbValues;


        bool locked = false;


 


        public int Height


        {


            get


            {


                return this.height;


            }


        }


 


        public int Width


        {


            get


            {


                return this.width;


            }


        }


 


        public FastBitmap(int x, int y)


        {


            width = x;


            height = y;


            image = new Bitmap(x, y);


        }


 


        public byte[] GetAllPixels()


        {


            return rgbValues;


        }


 


        public void SetAllPixels(byte[] pixels)


        {


            rgbValues = pixels;


        }


 


        public Color GetPixel(int x, int y)


        {


            int blue = rgbValues[(y * image.Width + x) * 3];


            int green = rgbValues[(y * image.Width + x) * 3 + 1];


            int red = rgbValues[(y * image.Width + x) * 3 + 2];


 


            return Color.FromArgb(red, green, blue);


        }


 


        public void SetPixel(int x, int y, Color cIn)


        {


            rgbValues[(y * image.Width + x) * 3] = cIn.B;


            rgbValues[(y * image.Width + x) * 3 + 1] = cIn.G;


            rgbValues[(y * image.Width + x) * 3 + 2] = cIn.R;


        }


 


        public static implicit operator Image(FastBitmap bmp)


        {


            return bmp.image;


        }


 


        public static implicit operator Bitmap(FastBitmap bmp)


        {


            return bmp.image;


        }


       


        public void LockPixels()


        {


            LockPixels(new Rectangle(0, 0, image.Width, image.Height));


        }


 


        private void LockPixels(Rectangle area)


        {


            if (locked)


                return;


            locked = true;


            bitmapData = image.LockBits(area, ImageLockMode.ReadWrite,


                PixelFormat.Format24bppRgb);


            IntPtr ptr = bitmapData.Scan0;


            int stride = bitmapData.Stride;


            int numBytes = image.Width * image.Height * 3;


            rgbValues = new byte[numBytes];


            Marshal.Copy(ptr, rgbValues, 0, numBytes);


        }


 


        public void UnlockPixels()


        {


            if (!locked)


                return;


            locked = false;


            Marshal.Copy(rgbValues, 0, bitmapData.Scan0, image.Width * image.Height * 3);


            image.UnlockBits(bitmapData);


        }


    }


 


 


With the class completed we can move on to the inversion algorithm. This part is actually quite simple.


 


        public new static void DoFilter(FastBitmap image)


        {


            image.LockPixels();


            byte[] pixels = image.GetAllPixels();


            for (int i = 0; i < pixels.Length; i++)


            {


                pixels[i] = (byte)(255 – pixels[i]);


            }


            image.SetAllPixels(pixels);


            image.UnlockPixels();


        }


 


 


Now we have an algorithm that in union with our FastBitmap class can invert a 320×240 image nearly instantly on a mobile device.


 


Thanks for reading. Let me know what you thought about this by leaving a comment!


[Author:Roshan Khan]

Comments (30)

  1. Kevin Daly says:

    Very cool, and one of the clearest explanations I’ve seen of this technique.

    I noticed that you declare and populate a local variable "stride" but don’t seem to actually do anything with it…is that an omission that actually makes a difference or did it just turn out not to be needed?

  2. RoshanK says:

    Nice catch Kevin. The stride value is not needed there. However, it is good to use if you are manipulating smaller portions of the image – or you care about the order the pixels are loaded in. Stride returns the size in bytes of a row of pixels. It also tells you if the pixels are loaded top down or bottom up (positive stride is top down, and negative stride is bottom up IIRC).

  3. Bruce Partington says:

    are wpf namespaces available on the compact framework, i haven’t had time to explore?

    in wpf, bitmapsource takes raw data as input and any filters can be applied without having to use unsafe methods. however we can also expose the underlying wic calls via unsafe methods if needed. using the byte array for processing is very fast and rendering in wpf is also high performance as well.

  4. Bruce, WPF isn’t available on the Windows CE or Windows Mobile platform(s) and hence the Compact Framework doesn’t support it.

    Silverlight support for Windows Mobile however is aiming for public preview later this year.

  5. ramond says:

    Marshal.Copy is very expensive, why don’t you store the pointer in an instance variable instead of copying all of the data.

  6. Matt says:

    More posts like this would be much appreciated.  Any tricks and improvements that developers don’t even realize exist – that’s just the kind of thing I need to see.  I’ll keep subscribing to this RSS feed, just keep coming with the optimized code!

  7. Bob says:

    Great article!  However, it seems your doing some double check locking on your LockPixels and UnlockPixels methods.  Would it not be better to either run synchronized ([MethodImpl(MethodImplOptions.Synchronized)]) or lock(this){…}?

  8. panefsky says:

    Very informing. thanx

    Please post more often here.

    I am subscribed for some time now but I was expecting this to be a more active blog!

    What’s wrong with you people???

    🙂 just kidding

  9. Eltawil says:

    I bet you had a lot of fun working with Assembly 🙂

  10. Tom says:

    Very good article, thanks.

    I wonder how this code perdorms compared to the C++ variant. I guess if I could use BitBlt, etc. directly (and the Invert-Operation with it) it would be much faster – Is this image data internally a DDB oder a DIB – if it is the former one could use BitBlts directly?

  11. Synaptime says:

    Hi,

    I tried this code out (VS 2005, WinMoPro6 device project)

    I have a very simple setup: A PictureBox (docked full in the form) as the image container, and the PictureBox.Image = new Bitmap(screen width,screen height).

    It takes about a second to invert.

    (both on the emulator, and the actual device)

    Any ideas why so slow?

    thanks

  12. Stephen says:

    This class has a few bugs in it.  (Mainly using width instead of stride).

    Because it got me started I am posting my fixed version.  This will work with bitmaps that have a stride that is not exactly = 3 * the width.

    public class FastBitmap

    {

       private Bitmap image;

       private BitmapData bitmapData;

       private int height;

       private int width;

       private byte[] rgbValues;

       bool locked = false;

       public int Height

       {

           get { return this.height; }

       }

       public int Width

       {

           get { return this.width; }

       }

       public FastBitmap(int x, int y)

       {

           width = x;

           height = y;

           image = new Bitmap(x, y);

       }

       public FastBitmap(Bitmap bitmap, bool createCopy)

       {

           width = bitmap.Width;

           height = bitmap.Height;

           if (createCopy == true)

               image = new Bitmap(bitmap);

           else

               image = bitmap;

       }

       public byte[] GetAllPixels()

       {

           return rgbValues;

       }

       public void SetAllPixels(byte[] pixels)

       {

           rgbValues = pixels;

       }

       public Color GetPixel(int x, int y)

       {

           int blue = rgbValues[(y * bitmapData.Stride + (x * 3))];

           int green = rgbValues[(y * bitmapData.Stride + (x * 3)) + 1];

           int red = rgbValues[(y * bitmapData.Stride + (x * 3)) + 2];

           return Color.FromArgb(red, green, blue);

       }

       public void SetPixel(int x, int y, Color cIn)

       {

           rgbValues[(y * bitmapData.Stride + (x * 3))] = cIn.B;

           rgbValues[(y * bitmapData.Stride + (x * 3)) + 1] = cIn.G;

           rgbValues[(y * bitmapData.Stride + (x * 3)) + 2] = cIn.R;

       }

       public static implicit operator Image(FastBitmap bmp)

       {

           return bmp.image;

       }

       public static implicit operator Bitmap(FastBitmap bmp)

       {

           return bmp.image;

       }

       public void LockPixels()

       {

           LockPixels(new Rectangle(0, 0, image.Width, image.Height));

       }

       private void LockPixels(Rectangle area)

       {

           if (locked)

               return;

           locked = true;

           bitmapData = image.LockBits(area, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

           IntPtr ptr = bitmapData.Scan0;

           int numBytes = bitmapData.Stride * image.Height;

           rgbValues = new byte[numBytes];

           Marshal.Copy(ptr, rgbValues, 0, numBytes);

       }

       public void UnlockPixels()

       {

           if (!locked)

               return;

           locked = false;

           Marshal.Copy(rgbValues, 0, bitmapData.Scan0, image.Width * image.Height * 3);

           image.UnlockBits(bitmapData);

       }

    }

  13. Klay says:

    Maybe I’m misunderstanding something here, but both versions posted seem to be broken.

    Instead of the inversion algorithm, I tried simply creating a new bitmap and setting all pixels to white.

    private void clearImage() {

       bmp.LockPixels();

       byte[] pixels = bmp.GetAllPixels();

       for (int i = 0; i < pixels.Length; i++) {

    pixels[i] = (byte)(255);

       }

       bmp.SetAllPixels(pixels);

       bmp.UnlockPixels();

       canvas.Image = bmp;

    }

    If I set the width of the bitmap to something that isn’t a multiple of 4, there is a single almost-full scan line of black pixels at the bottom of the image.

    Any fixes?

  14. Stephen says:

    You are right Klay.  I left in one reference to using Width where it should not have been (in the UnlockPixels() method).  This caused it to not copy all of the changed pixels back into to image.

    Here is the correct version of the class.

    public class FastBitmap

    {

       private Bitmap image;

       private BitmapData bitmapData;

       private int height;

       private int width;

       private byte[] rgbValues;

       bool locked = false;

       public int Height

       {

           get { return this.height; }

       }

       public int Width

       {

           get { return this.width; }

       }

       public FastBitmap(int x, int y)

       {

           width = x;

           height = y;

           image = new Bitmap(x, y);

       }

       public FastBitmap(Bitmap bitmap, bool createCopy)

       {

           width = bitmap.Width;

           height = bitmap.Height;

           if (createCopy == true)

               image = new Bitmap(bitmap);

           else

               image = bitmap;

       }

       public byte[] GetAllPixels()

       {

           return rgbValues;

       }

       public void SetAllPixels(byte[] pixels)

       {

           rgbValues = pixels;

       }

       public Color GetPixel(int x, int y)

       {

           int blue = rgbValues[(y * bitmapData.Stride + (x * 3))];

           int green = rgbValues[(y * bitmapData.Stride + (x * 3)) + 1];

           int red = rgbValues[(y * bitmapData.Stride + (x * 3)) + 2];

           return Color.FromArgb(red, green, blue);

       }

       public void SetPixel(int x, int y, Color cIn)

       {

           rgbValues[(y * bitmapData.Stride + (x * 3))] = cIn.B;

           rgbValues[(y * bitmapData.Stride + (x * 3)) + 1] = cIn.G;

           rgbValues[(y * bitmapData.Stride + (x * 3)) + 2] = cIn.R;

       }

       public static implicit operator Image(FastBitmap bmp)

       {

           return bmp.image;

       }

       public static implicit operator Bitmap(FastBitmap bmp)

       {

           return bmp.image;

       }

       public void LockPixels()

       {

           LockPixels(new Rectangle(0, 0, image.Width, image.Height));

       }

       private void LockPixels(Rectangle area)

       {

           if (locked)

               return;

           locked = true;

           bitmapData = image.LockBits(area, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

           IntPtr ptr = bitmapData.Scan0;

           int numBytes = bitmapData.Stride * image.Height;

           rgbValues = new byte[numBytes];

           Marshal.Copy(ptr, rgbValues, 0, numBytes);

       }

       public void UnlockPixels()

       {

           if (!locked)

               return;

           locked = false;

           Marshal.Copy(rgbValues, 0, bitmapData.Scan0,  bitmapData.Stride * image.Height);

           image.UnlockBits(bitmapData);

       }

    }

  15. Paulo Ricca says:

    Hey people…

    I was using both RoshanK and Stephen classes and you both missed one thing.

    specially RoshanK, for example:

    public void SetPixel(int x, int y, Color cIn)

    {

     rgbValues[(y * image.Width + x) * 3] = cIn.B;

     rgbValues[(y * image.Width + x) * 3 + 1] = cIn.G;

     rgbValues[(y * image.Width + x) * 3 + 2] = cIn.R;

    }

    You make three references to image.Width. This is a very very slow process. If you want some optimization you could use:

    public void SetPixel(int x, int y, Color cIn)

    {

     int w = image.Width;

     rgbValues[(y * w + x) * 3] = cIn.B;

     rgbValues[(y * w + x) * 3 + 1] = cIn.G;

     rgbValues[(y * w + x) * 3 + 2] = cIn.R;

    }

    which is much faster, try it! 🙂

    but… you already have a global variable for Width. so you could use instead:

    public void SetPixel(int x, int y, Color cIn)

    {

     int w = width;

     rgbValues[(y * w + x) * 3] = cIn.B;

     rgbValues[(y * w + x) * 3 + 1] = cIn.G;

     rgbValues[(y * w + x) * 3 + 2] = cIn.R;

    }

    which is even faster.

    In Stephen’s class he uses bitmapData.Stride which is also slow.. so i create a global variable for that and I define is when we lock the pixels, and use it just like I explained before.

    I added some other classes too, in order to access and set the pixels faster, so below is my version of this class.

    These are some common optimization stuff and they work very effectively although they aren’t very intuitive. Hope it was useful!

    using System;

    using System.Runtime.InteropServices;

    using System.Drawing;

    using System.Drawing.Imaging;

    public class FastBitmap

    {

       private Bitmap image;

       private BitmapData bitmapData;

       private int height;

       private int width;

       private int stride;

       private byte[] rgbValues;

       bool locked = false;

       public int Height

       {

           get { return this.height; }

       }

       public int Width

       {

           get { return this.width; }

       }

       public FastBitmap(int x, int y)

       {

           width = x;

           height = y;

           image = new Bitmap(x, y);

       }

       public FastBitmap(Bitmap bitmap, bool createCopy)

       {

           width = bitmap.Width;

           height = bitmap.Height;

           if (createCopy == true)

               image = new Bitmap(bitmap);

           else

               image = bitmap;

       }

       public byte[] GetAllPixels()

       {

           return rgbValues;

       }

       public void SetAllPixels(byte[] pixels)

       {

           rgbValues = pixels;

       }

       public Color GetPixel(int x, int y)

       {

           int s = stride;

           int blue = rgbValues[(y * s + (x * 3))];

           int green = rgbValues[(y * s + (x * 3)) + 1];

           int red = rgbValues[(y * s + (x * 3)) + 2];

           return Color.FromArgb(red, green, blue);

       }

       public byte[] GetPixelValues(int x, int y)

       {

           int w = width;

           int s = stride;

           byte[] c = new byte[3];

           c[2] = rgbValues[(y * s + (x * 3))];

           c[1] = rgbValues[(y * s + (x * 3)) + 1];

           c[0] = rgbValues[(y * s + (x * 3)) + 2];

           return c;

       }

       public void SetPixel(int x, int y, Color cIn)

       {

           int s = stride;

           rgbValues[(y * s + (x * 3))] = cIn.B;

           rgbValues[(y * s + (x * 3)) + 1] = cIn.G;

           rgbValues[(y * s + (x * 3)) + 2] = cIn.R;

       }

       public void SetPixel(int x, int y, byte r, byte g, byte b)

       {

           int w = width;

           int s = stride;

           rgbValues[(y * s + (x * 3))] = b;

           rgbValues[(y * s + (x * 3)) + 1] = g;

           rgbValues[(y * s + (x * 3)) + 2] = r;

       }

       public static implicit operator Image(FastBitmap bmp)

       {

           return bmp.image;

       }

       public static implicit operator Bitmap(FastBitmap bmp)

       {

           return bmp.image;

       }

       public void LockBitmap()

       {

           LockBitmap(new Rectangle(0, 0, width, height));

       }

       private void LockBitmap(Rectangle area)

       {

           if (locked) return;

           locked = true;

           bitmapData = image.LockBits(area, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

           stride = bitmapData.Stride;

           IntPtr ptr = bitmapData.Scan0;

           int numBytes = bitmapData.Stride * height;

           rgbValues = new byte[numBytes];

           Marshal.Copy(ptr, rgbValues, 0, numBytes);

       }

       public void UnlockBitmap()

       {

           if (!locked) return;

           locked = false;

           Marshal.Copy(rgbValues, 0, bitmapData.Scan0, bitmapData.Stride * image.Height);

           image.UnlockBits(bitmapData);

       }

    }

  16. Paulo Ricca says:

    Another thing. I found some months ago a class that was somewhat like this one, which I also changed to become faster and more useful

    I’ve added the implicit operator too (nice touch, RoshanK 😉 )

    I made this class completely compatible with the previous updated version of RoshanK’s class, so you can just change the class type from FastBitmap to UnsafeBitmap and allow unsafe code in the project build parameters, and test it in your program. I think its a bit faster, it doesn’t use Marshal, and it uses pointers.

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Drawing;

    using System.Drawing.Imaging;

    namespace Utility

    {

       public unsafe class UnsafeBitmap

       {

           Bitmap bitmap;

           int width;

           public int Width, Height;

           BitmapData bitmapData = null;

           Byte* pBase = null;

           public UnsafeBitmap(Bitmap bitmap)

           {

               this.bitmap = new Bitmap(bitmap);

               Width = bitmap.Width;

               Height = bitmap.Height;

           }

           public UnsafeBitmap(int width, int height)

           {

               this.bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);

               Width = bitmap.Width;

               Height = bitmap.Height;

           }

           public void Dispose()

           {

               bitmap.Dispose();

           }

           public Bitmap Bitmap

           {

               get

               {

                   return (bitmap);

               }

           }

           public struct PixelData

           {

               public byte blue;

               public byte green;

               public byte red;

               public static bool operator ==(PixelData a, PixelData b)

               {

                   // If both are null, or both are same instance, return true.

                   if (System.Object.ReferenceEquals(a, b))

                   {

                       return true;

                   }

                   // If one is null, but not both, return false.

                   if (((object)a == null) || ((object)b == null))

                   {

                       return false;

                   }

                   // Return true if the fields match:

                   return a.red == b.red && a.green == b.green && a.blue == b.blue;

               }

               public static bool operator !=(PixelData a, PixelData b)

               {

                   return !(a == b);

               }

               public override bool Equals(object obj)

               {

                   return base.Equals(obj);

               }

               public override int GetHashCode()

               {

                   return base.GetHashCode();

               }

           }

           private Point PixelSize

           {

               get

               {

                   Size st = bitmap.Size;

                   RectangleF bounds = new RectangleF(0, 0, st.Width, st.Height);

                   return new Point((int)bounds.Width, (int)bounds.Height);

               }

           }

           public void LockBitmap()

           {

               RectangleF boundsF = new RectangleF(0, 0, bitmap.Width, bitmap.Height);

               Rectangle bounds = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

               width = (int)boundsF.Width * sizeof(PixelData);

               if (width % 4 != 0)

               {

                   width = 4 * (width / 4 + 1);

               }

               bitmapData = bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

               pBase = (Byte*)bitmapData.Scan0.ToPointer();

           }

           public PixelData GetPixel(int x, int y)

           {

               PixelData returnValue = *PixelAt(x, y);

               return returnValue;

           }

           public byte[] GetPixelValues(int x, int y)

           {

               byte[] c = new byte[3];

               PixelData* returnValue = PixelAt(x, y);

               c[0] = returnValue->red;

               c[1] = returnValue->green;

               c[2] = returnValue->blue;

               return c;

           }

           public void SetPixel(int x, int y, PixelData color)

           {

               PixelData* pixel = PixelAt(x, y);

               *pixel = color;

           }

           public void SetPixel(int x, int y, byte r, byte g, byte b)

           {

               PixelData* pixel = PixelAt(x, y);

               pixel->blue = b;

               pixel->green = g;

               pixel->red = r;

           }

           public void UnlockBitmap()

           {

               bitmap.UnlockBits(bitmapData);

               bitmapData = null;

               pBase = null;

           }

           public PixelData* PixelAt(int x, int y)

           {

               return (PixelData*)(pBase + y * width + x * sizeof(PixelData));

           }

           public static implicit operator Image(UnsafeBitmap bmp)

           {

               return bmp.bitmap;

           }

           public static implicit operator Bitmap(UnsafeBitmap bmp)

           {

               return bmp.bitmap;

           }

       }

    }

  17. cybervedaa says:

    guys, i need to draw a random polygon that is semi-transparent. Windows Mobile does not support Color.FromArgb(). is there any other simple workaround to this??

  18. Tom says:

    hm, I did this by writing my own rasterizer in unmanaged c++ 🙂

  19. Robert says:

    like Tom said do yo have to take care of everything by yourself. Seme transparent means that the stuff below the polygon can be seen through it, so you can not fill the polygon with a constant color. For this you need to implement your own fill algorithm which evaluates the color of every pixel of the polygon.

    You could surely do this with the FastBitmap class and draw a polygon onto the FastImage – still you need to implement the filling and drawing by yourself (as long no one posts something to this) 🙂 – but I think it can be done. If you go this way the polygon can only "see" things that are also drawn on the FastImage – it can not see through.

  20. Le Sage says:

    Hum… weird…

    I’m using either version of the class, & in LockPixels (LockBitmap in Paulo Ricca’s version), after the initialisation of the bitmapData, for a 49×49 picture the bitmapData.Stride is said to be 148, but it should be 49*49=147, so I have errors in my image. :-

    Any idea why?

    Compact framework 2, VS08…

  21. Le Sage says:

    Answer to myself (& to whom it might help) : the stride (number of bytes occupied by a row) HAS TO be a multiple of 4 bytes (don’t ask me why), see the MSDN : http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride.aspx

    "The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary."

    That’s why sometimes after the first row there is a data shift in some pictures manually created. 🙂

  22. Max says:

    Hi guys, just a question why i get a ArgumentException when i excute this code :

                   Bitmap enfin = (Bitmap)image.Clone();

                   bitmapData = enfin.LockBits(rec, ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);

    Thank you

  23. Patrick Scott says:

    the only thing that I can see to improve the calculation is to change

           public void LockBitmap()

           {

               if ((width & 3) != 0)

               {

                   width = (width ^ 3) + 4;

               }

    }

    since binary operators should be faster than division

  24. Patrick Scott says:

    I believe Le Sage wonder why groups of 4 bytes and if I remember correctly it

    first byte => shades of gray

    second byte => shades of red

    third byte => shades of green

    forth byte => shades of blue

    with 0 thru 255 possible shades for each

  25. Patrick Scott says:

    Great blog!  I was able to understand and I got the code to work!  Can’t beat that.

    Keep up the great work.

    From an old C programmer.

  26. Yogusmilu says:

    What Paulo Ricco is very much true

    if RoshanK had already declared the global variable then why cant be use this.

    This is really faster and good piece of code.

    public void SetPixel(int x, int y, Color cIn)

    {

    int w = width;

    rgbValues[(y * w + x) * 3] = cIn.B;

    rgbValues[(y * w + x) * 3 + 1] = cIn.G;

    rgbValues[(y * w + x) * 3 + 2] = cIn.R;

    }

    Thanks

    Yogusmilu

  27. crafty says:

    @cybervedaa

    I’d look at P/Invoking the AlphaBlend function.  See here:  http://blogs.msdn.com/chrislorton/archive/2006/04/07/570649.aspx

  28. RoshanK says:

    Unfortunatly P/Invoke is slow. You are going to take a big hit for using it.

  29. romario says:

    hi all,

    1st of thanks for the lesson and the comments. one questio, how can I merge text to the bitmap? (for intace the date)

  30. Karina says:

    Hii all

    I thingk about. I have 2 function

    public void LockBit()

           {

               // Lock the bitmap’s bits.  

               Rectangle rect = new Rectangle(0, 0, input_image_width, input_image_height);

               bmdata = input_image.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //bmdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

               int RowsByte = bmdata.Stride;//so byte tren 1 hang

               int TotalSize = RowsByte * bmdata.Height;

               rgbValues = new byte[TotalSize];

               // Get the address of the first line.

               IntPtr ptr = bmdata.Scan0;

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

              // MessageBox.Show(RowsByte.ToString());

               //MessageBox.Show(i.ToString());

           }

           public void UnLockBit()

           {

               int TotalSize = bmdata.Stride * bmdata.Height;

               //byte[] rgbValues = new byte[TotalSize];

               // Get the address of the first line.

               IntPtr ptr = bmdata.Scan0;

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

               input_image.UnlockBits(bmdata);

           }

    and after i using

    LockBit();

               for (int i = 0; i < rgbValues.Length-2; i++)

               {

                   //rgbValues[i] = (byte)(255 – rgbValues[i]);  

                    rgbValues[i] = (byte)(rgbValues[i]/3+rgbValues[i+1]/3+rgbValues[i+2]/3);

               }

                  UnLockBit();

               pictureBox1.Refresh();

    this oke and verry fast