Manipulating Images with ImageMagik

As far as toolkits to handle images go, the .NET eco-sphere has more than an abundance.

From toolkits that are specifically designed to complement .NET right through to kits ported from other platforms such as GD, there’s no shortage of tools and APIs to do pretty much anything you might desire.

There’s one toolkit, however, that’s almost prehistoric when it comes to life time and that’s ImageMagik (IM for short). IM, to the best of my knowledge, has been around since the earliest of days in computing, and I certainly remember seeing it on the Commodore Amiga in the early 1980s, and it certainly existed on Unix systems before that.

IM’s strength, however, doesn’t come from its history; it comes from its staggering ability to do anything to pretty much anything as long as it’s image related. IM is available both as a set of command line tools and API/Software development libraries for just about every language under the sun, not just .NET.

Just to give you an idea of the amount of options available, here are some screen shots of the main convert commands help output:

Magik01

Magik02

Magik03

Magik04
Figure 1(a-d): The main convert commands

Yes, you did see that right, it really did take four, large 50-line console windows to get all the options that the toolkit provides. However, the point of this post is not to introduce you to the command line interface. If you want to install the command line tools, you can visit

http://www.imagemagick.org/

to download the bits you need. For the API options we are going to look at, you don’t need the download from the main website because the actual API library contains everything needed in a standalone package that can either be installed using NuGet or downloaded and added manually from the project home page on Codeplex at:

https://magick.codeplex.com/

Magik05
Figure 2: The IM application

For our examples, we’re going to do this the easy way and just use NuGet to install the bits we need. Before we do that, however, please do note the following points:

  • The current phase of ImageMagik (Tools and API) is rather transitional at present, in that they are currently undergoing a major update. This update is being described at the v6 to v7 update, and large portions of the core library are being re-written to handle new standards as well as improving the code base.
  • The current version (v7) is being described as a “Beta” version. (The reality of my testing, however, is that it is indeed very stable.) There are still v6 downloads available, but the automatic installers are all v7.
  • The version currently available as default on NuGet is the v7 build.

ImageMagik, under the hood, is also partially a non-managed assembly, so there are some cases where you might have to set your project configuration explicitly to 32 bit or 64 bit, rather than AnyCPU, which is the default.

There is an AnyCPU build, and, where possible, you’re advised to use that version of the library. The AnyCPU build contains both 32 & 64 bit versions as embedded resources, which it then unpacks and uses at runtime as required.

One last thing you also need to take note of is the “Graphics Component Bit Size”. If you list all the available packages on the NuGet Site at

https://www.nuget.org/profiles/dlemstra/

you’ll see that they all have “Q8” and “Q16” in the file names. This Q number tells you the maximum size of a graphics component the lib can handle.

The “Q8” builds can handle a maximum of 8 bits per pixel, which means the maximum image type that can be handled is a 32-bit RGBA (8 Bits Red, 8 Bits Green, 8 Bits Blue, 8 Bits Alpha) image.

The “Q16” builds can handle twice the colour resolution, and so are fully capable of handling high definition HDR output from systems such as broadcast rendering systems, high definition 3D software, and HD Video devices.

The reason the library is split into two separate branches like this is purely for performance. Most general day to day use cases will not require more than 8 bits per pixel.

If all you’re doing is manipulating images for an ASP.NET website or something similar, you really don’t need anything other than a “Q8” build. If, however, you’re producing broadcast quality imagery for the film and TV industry, it’s likely you’ll need the “Q16” version, but be aware, a normal standard spec PC will struggle.

“Q16” uses more than double the amount of memory, disk space, and resources (not to mention CPU processing time) than its smaller cousin. If you’re using a “Q16” build, make sure you have a beefy system, and that you actually do need to use it. It’s definitely NOT recommended to try using it with a standard build ASP.NET MVC application, even running on a 64 bit IIS7.5 server, I speak from experience on this one. 🙂

Shut Up, Shawty, and Show Me Some Code…

Okay then, as per usual for most of my posts, fire up Visual Studio and start yourself a standard console mode application.

Once your project is created, head to NuGet and do an online search for “Magick”. From the list, install the “Q8” AnyCPU version:

Magik06
Figure 3: Installing the “Q8” AnyCPU version

The first thing we’re going to do is get some basic information on an image file we have. Find an appropriate image and add it to your project as a “Content” item, and make sure it’s set to “Copy to build folder only if newer.”

I’ve found and added one of the many lolcat images I have floating around.

Magik07
Figure 4: Adding an image to the list

In your code, add the following:

using System;
using ImageMagick;

namespace imagemagik_blogpost
{
   class Program
   {
      static void Main()
      {
         MagickImageInfo myImageInfo =
            new MagickImageInfo("lolcat.jpg");

         Console.WriteLine("Image Width        :
            {0} pixels",myImageInfo.Width);
         Console.WriteLine("Image Height       :
            {0} pixels", myImageInfo.Height);
         Console.WriteLine("Image Colourspace  :
            {0}", myImageInfo.ColorSpace);
         Console.WriteLine("Image Format       :
            {0}", myImageInfo.Format);
         Console.WriteLine("Image X resolution :
            {0} Dpi", myImageInfo.ResolutionX);
         Console.WriteLine("Image Y resolution :
            {0} Dpi", myImageInfo.ResolutionY);

      }
   }
}

and then press F5 to run your program (remember to change the image name to the one you use). You should see something like the following:

Magik08
Figure 5: Info on your chosen image

You can read an image in lots of different ways. You can load it from disk as we’ve done here, or you can load it from a byte array, a media server stream, or database. There are lots of different examples on the codeplex documentation page for the project, and I have to say as far as projects go, this one is easily one of the better ones I’ve seen for the documentation available.

Next up, we’ll convert our lolcat jpeg to a ‘gif’, ‘bmp’, and a ‘png’. Change the code in your program so that it looks as follows:

static void Main()
{
   using (MagickImage MyImage =
      new MagickImage("lolcat.jpg"))
   {
      MyImage.Write("lolcat.bmp");
      MyImage.Write("lolcat.png");
      MyImage.Write("lolcat.gif");
   }
}

When you run this, you’ll not see any output (unless something goes wrong), but if you look in the folder where your project was built, you should now see that you have four different versions of your picture:

Magik09
Figure 6: You now have four versions of your lolcat image

Bear in mind also that IM can handle multi-frame images such as animated GIFs. It can convert multiple-frame single files into a series of frames in a different format, and can combine single frames into an animated GIF. The examples for this are a tad long, however, and the ones on the codeplex site are annotated way better than anything I can do here.

One task that IM is often used for is to resize images on the fly. This can be performed very easily by using the following code:

static void Main()
{
   using (MagickImage MyImage =
      new MagickImage("lolcat.jpg"))
   {
      MyImage.Resize(100, 100);
      MyImage.Write("lolcat-100x100.jpg");
   }
}

Which, in my case, re-sizes my image to 100×67 because IM tries to keep the aspect ratio correct where possible. If you don’t want it to maintain the ratio, you need to pass in some options by using the various overrides available to the resize method call, all of which is documented in detail on the codeplex page.

The last task I’m going to demonstrate is combining two images together. For this task, I’ve found an “Approved” stamp from the Internet, as shown in Figure 7:

Magik10
Figure 7: The “stamp of approval”

The stamp is transparent, so we’ll use it to overlay on our lolcat image.

Change your main program so it looks like:

static void Main()
{
   using (MagickImageCollection imagesToMerge =
      new MagickImageCollection())
   {
      MagickImage baseImage = new MagickImage("lolcat.jpg");
      imagesToMerge.Add(baseImage);

      MagickImage approvedStamp = new MagickImage("approved.png");
      imagesToMerge.Add(approvedStamp);

      using (MagickImage approvedlolcat = imagesToMerge.Mosaic())
      {
         approvedlolcat.Write("approvedlolcat.png");
      }
   }
}

and then press F5 to run it. As with the previous examples, you won’t see any output in the console, but if you look in the folder where your program was built, you should see a new image called “approvedlolcat.png”. If you open this paint in an image viewer, such as the Windows Picture Viewer, you should see your lolcat picture now has an approved stamp on it.

Magik11
Figure 8: The lolcat image is approved

.NET is a wonderful framework, but it’s also very large, and has an unimaginable amount of 3rd party additions. If you’ve heard of a toolkit you’d like to use but don’t know how, or you’ve found a strange API call that you’d like to know the purpose of, feel free to come hunt me down on Twitter as ‘@shawty_ds’. Your suggestion/question might even feature in a future post.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read