A Few ImageMagick C Examples
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:
- Arguments 2 and 3 are the origin.
- Arguments 4 and 5 are the width and height.
Therefore, we pick here the entire image. The function returns an array of PixelPacket
s, each containing 3 Quantum
s: red, green and blue. Last I checked, a Quantum
is an unsigned int
eger, i.e. 2 bytes, i.e. a colour taking values clamped in [0,65535]
.