Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image cropping and resizing ImageMagick vs GDI+ in C#

I have a web application where users can upload pictures to create their galleries. Years ago when I wrote the application I choose ImageMagick, and I did all my cropping and resizing with ImageMagick.

Now that I am rewriting the application from scratch, I replaced ImageMagick with native GDI+ operations, but the more I learn around GDI+ the more I am scared I made the wrong choice.

Everywhere I read that GDI+ is for the desktop and should not be used on a server application. I don't know the details, but I guess it's for the memory consumption, and indeed I can see GDI+ is using more memory to do the same operation (crop and resize) over the same image than ImageMagick (while to be honest GDI+ is faster).

I believed GDI+, ImageMagick or any other library should be more or less the same for those basic operations, and I liked the idea of using native GDI+ believing whatever MS is shipping with .NET should be at least OK.

What is the right approach/tool to use?

This is the code I use to crop:

internal Image Crop(Image image, Rectangle r)
{
    Bitmap bmpCrop;
    using (Bitmap bmpImage = new Bitmap(image))
    {
        bmpCrop = bmpImage.Clone(r, bmpImage.PixelFormat);
        bmpImage.Dispose();
    }
    return (Image)(bmpCrop);
}

This is the code I use to resize:

internal Image ResizeTo(Image sourceImage, int width, int height)
{
    System.Drawing.Image newImage = new Bitmap(width, height);
    using (Graphics gr = Graphics.FromImage(newImage))
    {
        gr.SmoothingMode = SmoothingMode.AntiAlias;
        gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
        gr.DrawImage(sourceImage, new Rectangle(0, 0, width, height));
        gr.Dispose();
    }
    return newImage;
}
like image 486
Max Favilli Avatar asked Jan 22 '26 13:01

Max Favilli


1 Answers

Can you link to somewhere people have said that GDI+ shouldn't be used on the server? Maybe they know something I don't.

I know a few things about how GDI+ works but nothing about ImageMagick. I did happen upon this page describing ImageMagick's architecture: http://www.imagemagick.org/script/architecture.php

It seems ImageMagick will internally convert images to an uncompressed format with 4 channels and a specific bit depth, typically 16 bits per channel, and do its work with the uncompressed data, which may be in memory or on disk depending on the size. 'identify -version' will tell you what your bit depth is. My impression is that in practice ImageMagick will typically work with a 64-bit RGBA buffer internally, unless you use a Q8 version which will use 32-bit RGBA. It also can use multiple threads, but I doubt that will matter unless you're working with very large images. (If you are working with very large images, ImageMagick is the clear winner.)

GDI+ Bitmap objects will always store uncompressed data in memory and will generally default to 32-bit RGBA. That and 32-bit RGB are probably the most efficient formats. GDI+ is a drawing library, and it wasn't designed for large images, but at least a Bitmap object won't hold any resources other than the memory for the pixel data and image metadata (contrary to popular belief, they do not contain HBITMAP objects).

So they seem very similar to me. I can't say one is clearly better than the other for your use case. If you go with imagemagick, you should probably use a Q8 build for the speed and memory gains, unless the extra precision is important to you.

It seems like if your only operations are load, save, scale, and crop, you should be able to easily replace the implementation later if you want.

Unless you need to work with metafiles, you should probably be using Bitmap objects internally and not Images. Then you wouldn't have to create an intermediate Bitmap object in your Crop function. That intermediate object may be behind some of the extra memory consumption you observed. If you get Image objects from an external source, I'd suggest trying to cast them to Bitmap and creating a new Bitmap if that doesn't work.

Also, the "using" statement calls Dispose automatically, so there's no need to also call it explicitly.

like image 93
Esme Povirk Avatar answered Jan 25 '26 07:01

Esme Povirk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!