During my search for a function to rotate images in C#, I came across the following post on dotnet-snippets.de: rotate images with C #.
Besides the method presented in the article there were 2 other approaches presented in the comments and so the question was: which method is the fastest of them.
Since this also awakened my interest, I wrote a small test application which checks every of those functions for their performance.
After a few test runs, it became clear that the original solution from the above mentioned post was not suitable because it created a new bitmap every run, what eats tons of memory. Thus, the following function has been excluded from the tests.
public Bitmap rotateImage(Bitmap bitmap, float angle) { Bitmap returnBitmap = new Bitmap(bitmap.Width, bitmap.Height); Graphics graphics = Graphics.FromImage(returnBitmap); graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2); graphics.RotateTransform(angle); graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2); graphics.DrawImage(bitmap, new Point(0, 0)); return returnBitmap; }
However, the following function, which is a slightly modified version from the original, was still tested.
public Bitmap rotateImageUsi(Bitmap bitmap, float angle) { using (Graphics graphics = Graphics.FromImage(bitmap)) { graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2); graphics.RotateTransform(angle); graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2); graphics.DrawImage(bitmap, new Point(0, 0)); } return bitmap; }
Also the following function, based on Bitmap-Class’ RotateFlip() function, was tested.
public Bitmap rotateInternalFunction(Bitmap bitmap) { bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); return bitmap; }
To test the speed I have taken the following compressed photo from last weekend.
(Click on image to get full size.)
Then I have used both functions to rotate the image by 180 ° for 10, 100, 250, 500, 1000, 5000 and 10000 times and measured the execution time for both.
int[] testruns = new int[]{10,100,250,500,1000,5000,10000}; Bitmap bmp = (Bitmap)Bitmap.FromFile(pic); string result = string.Empty; foreach (int x in testruns) { DateTime s2 = DateTime.Now; for (int i = 0; i < x; i++) { rotateImageUsi(bmp, 180f); } DateTime e2 = DateTime.Now; DateTime s3 = DateTime.Now; for (int i = 0; i < x; i++) { rotateInternalFunction(bmp); } DateTime e3 = DateTime.Now; TimeSpan t2 = new TimeSpan(e2.Ticks - s2.Ticks); TimeSpan t3 = new TimeSpan(e3.Ticks - s3.Ticks); result += "Test runs: " + x.ToString() + "rn" + t2.TotalMilliseconds.ToString() + "rn" + t3.TotalMilliseconds.ToString() + "rnrn==========================rn"; }
My test program returned the following results:
test runs | execution time in ms – Graphics-Object | execution time in ms – Bitmap.RotateFlip |
10 | 640 | 23 |
100 | 5327 | 167 |
250 | 10955 | 409 |
500 | 18641 | 758 |
1000 | 35375 | 1343 |
5000 | 232421 | 7270 |
10000 | 448424 | 9734 |
The testing environment was my laptop with an Intel Core i3 M330 processor, 4GB of RAM,. Net Framework 4 and Windows 7.
Looking at the results, it can be said that the RotateFlip() version is much faster, which becomes particularly clear when many images have to be processed.
But there’s nevertheless a reason why you should use the GDI+ variant in some cases: the arbitrary angle/degree of rotation.
If you now want to run your own tests, you can download my test project as a Visual Studio solution from here.
I note that you only rotate by one angle: 180 degrees…. I’m pretty sure that that’s a poor test because angles which are divisible by 90 will be optimised by some rotation algorithms… I suggest you re-run it with some arbitrary angles and also with different interpolation modes as mentioned by another commenter. :-)
Thanks for you tests.
Unfortunately, without specifying the InterpolationMode you used, they are not very meaningful.
I suggest you to try different values of Graphics.InterpolationMode, and then report the results.
You will find that different interpolation modes give very different performance results.
As far as I know, RotateFlip DOES use GDI+ behind the covers. So it is interesting to see how it out performs the native way :)
Hey ELNINO,
thanks for your notice. I’ve had a look into the System.Drawing.dll and must say, that you’re right! Image.RotateFlip() is also using GDI+.
So the reason, why Image.RotateFlip() is faster, seems to be in memory usage. RotateFlip wraps the native gdiplus.dll and calls the following function:
[DllImport(“gdiplus.dll”, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern int GdipImageRotateFlip(HandleRef image, int rotateFlipType);
So it looks like that using RotateFlip the picture is manipulted directly on memory (on the same memory address), while using the GraphicsObject there will be made some working copies before manipulating the original image.
But what do you mean by “see how it out performs the native way”? Could you please explain me in more detail or give me a short example?
Greets,
Raffi
p.s.: Please excuse my english skills. ;)
Hi Raffi,
Wow its nice to see you’ve dug into details :) I just commented on your results which shows that RotateFlip is faster than using the nativ GDI+ library calls. I had the impression that RotateFlip merely calls them behind the scenes so I was puzzled to see why or rather how it works faster. Now since you have found out how it actually does it, it all makes sense :) Thanks for giving heads up on the internals. Keep it up!
/ELNINO.
Hey ELNINO,
thanks for commenting again. At least as much you appreciate that i dug into details, I appreciate, that you came back and read my answer. ;)
By the way: I like your blog.