Creating/Manipulating images with gd LG #91

<< Prev | TOC | Front Page | Talkback | FAQ | Next >>

...making Linux just a little more fun! | Creating/Manipulating images with gd By Shuveb Hussain

gd is an open source library written for easy manipulation/creation of images. It lets you open images in formats like jpeg,png,xpm and a few more. You can think of gd as 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 like drawing lines, arcs, ellipses or rectangles on that image, and can finally store the resulting image back in any of the earlier mentioned formats. For exapmple, you could write a simple command line program that converts a given file in JPEG format to PNG using gd. gd can do more. It can change colors in the image, copy,cut, merge or rotate it. One more area where gd is useful is when you want to create images on the fly. With gd, you can programatically 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 got a GNU/Linux system that uses RPM to manage packages, try out

    	rpm -q gd

to find out if gd is installed. You can download the latest tarball from www.boutell.com

## Creating Images

The following program creates a 100 by 100 pixel black image with a white line running diagonally across it.

If you want to save some typing, use this listing

    /* 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 line:

    $ gcc gd-eg1.c -lgd

Run the resulting a.out file and you should have a test.jpg file created in the current directory. If you view it, you'll have a 100 by 100 pixel black image with a white line cutting across. The program, I'm sure is simple, butI'll explain the code a little.

    	gdImagePtr im; //declaration of the image

this declares a pointer to a gd image descriptor.

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

we now create an image 100 by 100 pixels and store the reference it returns in the variable im. This is much like a file handle. All further operations on this image shall be 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 to the image, you'll need to allocate color. Allocating color for the first time for a newly created image will make 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 will paint 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 to 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 on to a disk file in the JPEG format. The final argument of this function is the quality setting for JPEG format images. This can be between 1 and 100, where 100 is the highest quality. Passing -1 will use 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);

and you finally release memory allocated to hold the image data.

Please note that the PNG format is now enjoying good support and uses better compression algorithms. It also achieves something that the JPEG format does not : Transparency. GIF format images, though good enough, use the LZW compression algorithm patented by Unisys when using full compression. The GIF format support in gd was thus dropped recently. And you must have read about the hue and cry against software patents..... Some web sites even claim to be GIF free, like body sprays that claim to be "free of CFC, that damages friendly Ozone" More on this at www.burnallgifs.org

## Manipulating Images

gd also allows you to open and manipulate existing images apart from creating new ones from scratch. To illustrate this, the following program will open an image of Tux, enlarge it a little and write a 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.

Save some typing, use this listing

Before | After

    /* 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 more function calls. The functions are described below

###

    gdImageCopyResized

This gd function copies rectangular parts of one image to another. In the process of copying, it can also 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 rather use gdImageCopyResampled, which smoothens 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 gdImageCopy. To rotate the image as you copy, try the new gdImageCopyRotated function.

###

    gdImageStringFT

This function writes text on to the image using the freetype library, thus the trailing "FT" in the function name. You should have freetype installed 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)

In difficulty, this function returns a char pointer that points to an error message else returns 0. The brect array is filled up with the size of the bounding rectangle of the printed string. You can also determine the size of the bounding rectagle without actually printing a string. To do that pass NULL in the 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 TTF fonts in this function. If your needs are simple, you can use the function gdImageString. Freetype is not needed for this function to work properly, it uses any one of the five built in gd fonts.

Shuveb is a pervert by social compulsion sitting in a small but historical city in southern India. He thinks life is neither a Midsummer Night's Dream nor a Tempest, it's simply a Comedy Of Errors, to be lived As You Like It. Apart from being a part time philosopher, he is a seasoned C programmer who is often in confusion about what the * does to a pointer variable.... APR Bristol is the company that pays him for learning Linux.

Copyright © 2003, Shuveb Hussain. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 91 of Linux Gazette, June 2003

<< Prev | TOC | Front Page | Talkback | FAQ | Next >>