Creating/Manipulating Images with gd

by Shuveb Hussain

gd is an open-source library that allows users to create and manipulate images easily. It lets you open images in formats such as JPEG, PNG, XPM and a few more. gd works something like this: it opens images in different formats and converts them to generic bit-mapped images in memory. It then lets you do graphical operations, such as drawing lines, arcs, ellipses or rectangles on that image, and stores the resulting image in any of the earlier-mentioned formats. For example, you could write a simple command-line program that converts a given file in JPEG format to PNG using gd. gd also can change colors in the image and copy, cut, merge or rotate it.

In addition, gd is useful when you want to create images on the fly. With gd, you programmatically can create an image, color it, draw on it and save it to disk.

gd is best known for creating images on the fly for use in Web pages. This is made possible with the help of PHP.

If you have a GNU/Linux system that uses RPM to manage packages, run rpm -q gd to find out if gd is installed already. If not, you can download the latest tarball from here.

Creating Images

The following program creates a 100x100 pixel black image with a white line running diagonally across it, as shown here:


/* File : gd-eg1.c */
#include < gd.h >
#include < stdio.h >

int main() {
	gdImagePtr im; //declaration of the image
	FILE *out; //output file
	int black,white;

	im = gdImageCreate(100,100); //create an image, 100
by 100 pixels

	black = gdImageColorAllocate(im, 0, 0, 0); //
allocate black color
	white = gdImageColorAllocate(im, 255, 255, 255);	//
allocate white color	
	gdImageLine(im, 0, 0,100,100, white); // draw a line
using the allocated white color.

	out = fopen("test.jpg", "w"); //open a file
	gdImageJpeg(im, out, -1); //write the image to the
file using the default quality setting

	/* be good, clean up stuff */
	fclose(out); 
	gdImageDestroy(im);
}

Compile the program with the following command:


$ gcc gd-eg1.c -lgd

Run the resulting a.out file, and a test.jpg file will be created in the current directory. If you view it, you should see a 100x100 pixel black image with a white line cutting across. The program is pretty simple, but I'll explain the code a little.


	gdImagePtr im; //declaration of the image

declares a pointer to a gd image descriptor.

	

	im = gdImageCreate(100,100); //create an image, 
100 by 100 pixels

creates an image 100x100 pixels in size and stores the reference it returns in the variable im. This is much like a file handle. All further operations on this image are carried out using this reference.

	

	black = gdImageColorAllocate(im, 0, 0, 0); //
allocate black color
	white = gdImageColorAllocate(im, 255, 255, 255);	//
allocate white color

Before you can draw anything on the image, you need to allocate color. Allocating color for the first time in a newly created image makes it the background color for that image. The function gdImageColorAllocate takes four arguments. The first one is the image pointer and the next three are Red, Green and Blue values, respectively. Thus, calling gdImageColorAllocate(im, 0, 0, 0) for the newly created image paints the background of the new image black. We store the color indexes in variables, because graphical drawing or font drawing functions take a "color" argument.

	

	gdImageLine(im, 0, 0,100,100, white); // draw a line using the 
allocated white color.

This function draws a line from the top left corner (0,0) to the bottom right corner (100,100) using the color white on the image pointed to by im.


	gdImageJpeg(im, out, -1); //write the image to the file using the 
default quality setting

This is the function call that writes the image to a disk file in JPEG format. The final argument of this function is the quality setting for JPEG format images. This can be anything between 1 and 100, where 100 is the highest quality. Passing -1 uses the default quality setting. Similarly, there are other functions that store images in different formats:


	GdImagePng(im,out) // store as PNG (note no quality setting)

	GdImageGd and gdImageGd2 are functions that store images in formats 
specified by the library.

	gdImageDestroy(im);

Finally, you release memory allocated to hold the image data.

Note that the PNG format enjoys good support and uses better compression algorithms. It also achieves something that the JPEG format does not--transparency. GIF format images, although good enough, use the LZW compression algorithm patented by Unisys when using full compression. GIF format support in gd thus was dropped. And you must have read about the hue and cry against software patents; more on this here.

Manipulating Images

In addition to creating new images from scratch, gd also allows you to open and manipulate existing images. To illustrate this process, the following program opens an image of Tux, enlarges it a little and writes the string "Tux, the Linux Penguin" on to the image. Apart from drawing text on to the image, this program is intended to explain a few more functions that will be of use in your work with gd.


/* File : gd-eg2.c */
#include < gd.h >
#include < stdio.h >

int main() 
{
	gdImagePtr oldtux, newtux; //declaration of the image
pointers
	FILE *out, *in;
	int red,white;
	int brect[8];
	char *err;
	
	in = fopen("tuxin.jpg","r");
	oldtux = gdImageCreateFromJpeg(in);
	newtux = gdImageCreate(150,165); //create an image,
150 by 165 pixels

	white = gdImageColorAllocate(newtux, 255, 255,
255);// allocate white color	
	red = gdImageColorAllocate(newtux, 255, 0, 0); //
allocate black color

gdImageCopyResized(newtux,oldtux,0,0,0,0,150,150,oldtux->sx,oldtux->sy);
	
	err=gdImageStringFT(newtux,brect,
red,"/usr/X11R6/lib/X11/fonts/TTF/luxisr.ttf",10,0,0,160,"Tux
,The Linux Penguin");
	if(err)	fprintf(stderr,"Error : %s\n",err);

	out = fopen("tuxout.jpg", "w"); //open a file
	gdImagePng(newtux, out); //write the image to the
file in the PNG format

	/* be good, clean up stuff */
	fclose(out); 
	fclose(in);
	gdImageDestroy(oldtux);
	gdImageDestroy(newtux);
}

As you can see, this program uses a few additional function calls. The functions are described below:

gdImageCopyResized: copies rectangular parts of one image to another. In the process of copying, it also can resize the image. The function prototype is:


void gdImageCopyResized(gdImagePtr dst, gdImagePtr
src, int dstX, int dstY, int srcX, int srcY, int
destW, int destH, int srcW, int srcH);

The sx and sy members of the gdImagePtr structure hold the width and height of the image respectively.

You might have noticed that the image becomes tagged as a result of stretching. If you have gd version 2.0 or better, you could use the gdImageCopyResampled function instead, which smooths any rough edges formed as a result of stretching or shrinking. If you want to copy portions of the image with no resizing involved, then try the gdImageCopy function. To rotate the image as you copy it, try the gdImageCopyRotated function.

gdImageStringFT: writes text on to the image using the FreeType library, thus the trailing "FT" in the function name. You should have FreeType installed on your system, and your gd library should have been complied with FreeType support. The prototype is:


char *gdImageStringFT(gdImagePtr im, int *brect, int
fg, char *fontname, double ptsize, double angle, int
x, int y, char *string)

This function returns a char pointer that points to an error message or else it returns 0. The brect array is filled with the size of the bounding rectangle of the printed string. You also can determine the size of the bounding rectangle without actually printing a string. To do that, pass NULL in place of the image pointer argument. For some strange reason, you need to pass the absolute path of the font file to this function. So, even if you have a font file in the current directory, you need to provide the whole path. Only FT fonts are used in this function. If your needs are simple, you can use the function gdImageString, as FreeType is not needed for this function to work properly. It uses any one of the five built-in gd fonts.

Copyright (c) 2003, Shuveb Hussain. Originally published in Linux Gazette issue 91. Copyright (c) 2003, Specialized Systems Consultants, Inc.

Apart from being a part time philosopher, Shuveb is a seasoned C programmer who often is confused about what the * does to a pointer variable.

Load Disqus comments