Monday 16 April 2007

Writing a Pocket PC Paint Program in C#

Well I was rather annoyed that my PPC doesn't contain a Paint Program, a simple doodling program would be so amazing to show off to your friends. But I guess Microsoft doesn't know what nerds like.

So I thought about it and went about getting everything ready. After downloading a few things, such as the shiny new Windows Mobile 6 SDK with the PPC emulator 2. Shame really that I am only developing the program for WM5. Though I wouldn't mind having a shiny new Windows Mobile 6 device *hint* *hint*.

GDI has never really been that fast, even on a modern PC. Show just think what its like on my 200mhz Pocket PC Phone. So when I was looking into doing some of the coding for the graphics filters I thought there must be a better way. Below for example is a piece of code to inverse the colours on a bitmap using GDI.

private void Inverse(Bitmap bmp)
{
//Declare a colour to store the colour in each pixel
Color c;

//Iterate through each pixel
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
//Get the colour of the pixel
c = bmp.GetPixel(x,y);

//Set the colour of the inverted pixel
bmp.SetPixel(x, y, Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
}
}
}


Ok, so its quite fast for small images. But for my image editing programming program I want it to be editing sizes of 1000x1000 or more and at this size it takes a rather long time. So looking around MSDN I stumbled upon using Unsafe bitmaps, in which you can access the byte array of the image directly thus equalling awesome speed. Ok takes more coding but hell is it fast! Below is the new version of the inverse function.

private void Inverse(Bitmap bmp)
{
//Specify Pixel format
PixelFormat pxf = PixelFormat.Format24bppRgb;

//Create region of the bitmap to lock
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

//Lock original bitmap
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, pxf);

//Get address of the first line of the image
IntPtr ptr = bmpData.Scan0;

//Declare array to hold the bytes of the bitmap
int numBytes = bmp.Width * bmp.Height * 3;
byte[] rgbValues = new byte[numBytes];

// Copy the RGB values into the array.
Marshal.Copy(ptr, rgbValues, 0, numBytes);

for (int counter = 0; counter < rgbValues.Length; counter += 3)
{
//Store the new colour
rgbValues[counter] = 255 - rgbValues[counter];
rgbValues[counter + 1] = 255 - rgbValues[counter + 1];
rgbValues[counter + 2] = 255 - rgbValues[counter + 2];
}

// Copy the RGB values back to the bitmap
Marshal.Copy(rgbValues, 0, ptr, numBytes);

// Unlock the bits.
bmp.UnlockBits(bmpData);
}


Though now extra using statements have to be included, such as System.Drawing.Imaging and System.Runtime.InteropServices.

I hope you found this little snippet interesting, I will post more about the paint program soon, don't worry. Its currently got quite a lot of cool features, hopefully in the next couple of days there will be a download link also.

No comments: