Gamedev Geeks....

only geeks allowed :P...
See also: Other Geeks@INDC

Resize Bitmap Tutorial in .NET CF

As we know, .NET CF doesn't have standard routine to resize Bitmap (Don't know why...). I'm looking for a tutorial online, but it seems noone already wrote this. So I decide to do it by myself (that's why I wrote this post in English. I hope I can help everyone in need). Actually I need this code for my Butterfly Project (Imagine Cup 2008 - Software Design)

Well, let's get started..

The basic (and silly) idea of resizing image is by mapping pixel one by one based on the width and height ratio. So if we defined originalBitmap is a Bitmap file referencing to the original bitmap to be resized, and resultBitmap is a Bitmap reference where we should write it, the code should look like this: (assuming resultBitmap already referenced to an instance with a defined width and height)


for (int y = 0; y < resultBitmap.Height; ++y) {
   for (int x = 0; x < resultBitmap.Width; ++x) {
      resultBitmap.SetPixel(x, y, originalBitmap.GetPixel( (int)Math.Round(x * originalBitmap.Width / resultBitmap.Width), (int)Math.Round(y * originalBitmap.Height / resultBitmap.Height) ));
   } 


But we should forget the above code as soon as possible. We mustn't implement those kind of code. It looks like O(n*m) with n = height and m = width, but let's see... In every loop pass it calls SetPixel and GetPixel which will iterate the bitmap to get the pixel value we need (this was done every pass), and also there are many redundant value which is can be pre-computed to increase effectivity. Let's assume a setPixel and GetPixel pass consume O(n*m) too so the total will be O(n^3 * m^3).... -______- (it still use so many mathematical function inside..)

To decrease any redundant value, let's just use a temporary variable which stores the precomputed value (and also do this also for class parameter that was accessed badly every loop pass. It will be much efficient fecthing a value from stack than from calling an method.. Properties is a method too.) 

And for the SetPixel and GetPixel issue, I think we should go back using the traditional way, POINTER :D (I don't know why but I love pointer :P). Before we start using pointer in C# we should use unsafe tag in code containing the pointer and then use /unsafe when building or check the unsafe build in build properties when using visual studio.

The Final Code should looks like this:


public static void ResizeImage(Bitmap originalBitmap, Bitmap resultBitmap) {
    int newWidth = resultBitmap.Width;
    int newHeight = resultBitmap.Height;
    int originalWidth = originalBitmap.Width;
    int originalHeight = originalBitmap.Height;

    BitmapData originalData = originalBitmap.LockBits(
        new Rectangle(0, 0, originalWidth, originalHeight),
        ImageLockMode.ReadOnly,
        PixelFormat.Format32bppRgb);
    BitmapData resultData = resultBitmap.LockBits(
        new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height),
        ImageLockMode.WriteOnly,
        PixelFormat.Format32bppRgb);

    double xFactor = originalWidth / newWidth;
    double yFactor = originalHeight / newHeight * originalWidth;

    unsafe
    {
        int* originalPointer = (int*)originalData.Scan0.ToPointer();
        int* resultPointer = (int*)resultData.Scan0.ToPointer();

        for (int y = 0; y < newHeight; ++y) {
            for (int x =0; x < newWidth; ++x) {
                int sourcePosition = (int)(Math.Round(x * xFactor) + Math.Round(y * yFactor));
                int destinationPosition = (x + y * newWidth);
                resultPointer[destinationPosition] =
                    originalPointer[sourcePosition];
            }
        }
        originalBitmap.UnlockBits(originalData);
        resultBitmap.UnlockBits(resultData);
    }
}


Well, I don't think this was the optimal code.But I think I don't have any time to develop it further (its 6 AM... limit of zombie skills.. time to have 2-3 hours of sleep). Besides I think I'm a bit lazy to deploy this code to PDA (Thanks for Igor IF2004 for borrowing me the PDA..) every time I want to debug it.. So I hope all of you can improve this silly code :P. Let's see... Look at the line contain "int destinationPosition = (x + y * newWidth);". Do you think it's neccessary? We could just use a temp variable to contain the value and increase the value every pass, OR we could just increase the pointer every pass (its very efficient) :D. 

Thanks for reading :D :D :D 

P.S. Just Curious, Is there any tag to post code? like <code> in phpBB? 

Share this post: | | | |

Comments

Clawford said:

Oh... I forgot.. Those code can only be applied when we want to resize image to smaller size.. XD

I'm sorry bout this. I'll make better code next time.

# April 22, 2008 2:16 AM

ronald said:

if you using WLW you can use a different CSS to make your code more readable. Just like my post at geeks.netindonesia.net/.../ronald  

# April 22, 2008 9:58 AM

Clawford said:

mau dunk WLW nya XD

# April 27, 2008 1:13 PM

Pablo Grisafi said:

You do can resize in CF. Chech this page: blogs.msdn.com/.../910075.aspx

# July 31, 2008 2:00 AM