Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

A Few ImageMagick C Examples

9 Aug 2009

The ImageMagick suite offers CLIs to work with images of many formats. It also comes with an API for several languages. Here's what it looks like for C.

1 What Use for an API?

Given the superb command-line interface ImageMagick provides, it's questionable whether getting bogged down in a lower-level API makes any sense at all. Perhaps it does, if you don't like writing more advanced shell scripts, and it would certainly be understandable to prefer the C syntax. The ImageMagick C API comes with the high-level – a little too high, maybe – MagickWand interface and the not-that-low-level MagickCore one. Before long, I found myself more at home with MagickCore, and that's the one I'm illustrating here.

2 Build

A generally useful makefile would look like:

CFLAGS = `Wand-config --cflags`
LDFLAGS = `Wand-config --ldflags`
LIBS = `Wand-config --libs`
prog: main.c
    gcc $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)

3 Header File

The only one you'll need to include is as follows:

#include <magick/ImageMagick.h>

4 Basic Operation

4.1 Initialisation

You'll need to initialise the library:

InitializeMagick(*argv);

You'll also need for most operations to keep to hand an exception and an image information structure ready:

ExceptionInfo e;
GetExceptionInfo(&e);

ImageInfo *info;
info = CloneImageInfo(NULL);

4.2 Opening an Image

This depicts the sort of operations you will regularly get to carry out with MagickCore. You can in particular see how the exception and image information structures come into play:

Image *img;
strcpy(info->filename, "image.jpg");
img = ReadImage(info, &e);
CatchException(&e);

Once you get hold of such an Image, you're free to use the wealth of image manipulation functions the API offers to modify it.

4.3 Cleaning Up

It will come to no surprise that working with images is a memory-intensive business, and as such you'll want to be diligent and free the memory allocated to unused images:

DestroyImage(img);

Similarly, it will be worth tidying up if you're done with ImageMagick in the course of your program:

DestroyExceptionInfo(&exception);
DestroyMagick();

5 Loading Images without Files

Earlier on, we saw how to read an image from file. The following example shows how to create an Image from data you got elsewhere (e.g. a database). It's done by using the BlobToImage function. Assuming you have initialised the library properly (with an exception e) and you have len-bytes long JPEG data in a buf, you can do the following:

char *buf;       /* Already initialised */
size_t len;      /* Already initialised */

ImageInfo *info; /* Not yet initialised */
Image *img;      /* Not yet initialised */

info = CloneImageInfo(NULL);
img = BlobToImage(info, buf, len, &e);
CatchException(&e);

6 Working with Pixels

Once data from JPEG or another format has been decoded, it's possible to get the pixels right from the img we just created:

const PixelPacket *pxs; /* Every single pixel in the image */
Quantum r, g, b;        /* These are unsigned integers, but never mind */

pxs = AcquireImagePixels(img, 0, 0, WIDTH, HEIGHT, &e);
CatchException(&e);

/* Let's read the first pixel */
r = pxs[0].red;
g = pxs[0].green;
b = pxs[0].blue;
printf("%d %d %d\n", r, g, b);

The AcquireImagePixels() function takes a portion of the image:

Therefore, we pick here the entire image. The function returns an array of PixelPackets, each containing 3 Quantums: red, green and blue. Last I checked, a Quantum is an unsigned integer, i.e. 2 bytes, i.e. a colour taking values clamped in [0,65535].

7 References