User Tools

Site Tools


user:smeas:portfolio:hpc0project2

Creating Animated gifs with the GD Image Library

So, you see all these funny animated images people have made, and you wonder to yourself, “How do they do that? Is it magic? Sorcery? Wizardry?”

In all actuality, it's actually pretty simple! And this tutorial is going to show you how to use the GD library, and a really handy and simple Linux tool to create an animated gif of your very own!

Objectives

The purpose of this project is to create a procedurally generated set of images using the C programming language and the GD image library. The user will write a program which generates a set number of images, and then runs a Linux tool called “convert” (part of the “imagemagick” package) to compile the separate images into one animated .gif file.

Prerequisites

There are three prerequisites to this project.

  • Intermediate knowledge of C programming (and preferably the implementation of the GD image library)
  • A Linux machine with the GD Image Library installed
  • A Linux machine with the imagemagick package installed.

These packages are already installed on Lab46. If you plan on doing this on a different machine, however, you can find them in your distribution's repositories.

To install these on Ubuntu, or any other Debian based distribution, use the following commands:

GD Image Library

sudo apt-get install libgd2-xpm libgd2-xpm-dev imagemagick

Background

For the EOCE for C Programming, we were asked to use the GD image library to create a tree. I made a tree (albeit one that looked like it had been subjected to a nearby nuclear meltdown, possibly in the Ukraine), but wasn't quite satisfied. When someone mentioned to me, “You could probably make 100 different images, and then create a gif out of them”. This seemed like a fun idea to pursue, so, I did it.

It wasn't pretty, as each image was randomly generated. But I thought it was pretty fun to do. So, I decided to pass on my knowledge to others so they may also partake in creating gifs using the GD library (hopefully prettier ones, and not just entropic foliage).

Scope

Upon completion, you should have an animated gif created with the GD Image Library. If you follow the tutorial correctly, it will be a spiral made up of multi-colored circles. You will also have the basis for code upon completion that can be used to create other animated images.

Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gd.h>
#include <math.h>
 
#define BLACK           0
#define GRAY            1
#define VIOLET          2
#define INDIGO          3
#define BLUE            4
#define GREEN           5
#define YELLOW          6
#define ORANGE          7
#define RED             8
#define WHITE           9
 
#define PI              3.1415926535897

The first step is to set up our header files, and to define names for our colors to make things a little more readable. We also define the value of pi, as we will be using it to calculate our spiral. Also, if you plan to incorporate any random elements into your image generation, be sure to include the <time.h> header as well, so you can seed your random function.

int main(int argc, char* argv[])
{
	// Creation of file pointers for our output files and GD image
	FILE *out;
	gdImagePtr img;
 
	// Setting of the output files name formatting
	char format[] = "output/%02d.png";
	char outfile[sizeof format+100];
 
	// Instantiation of the array of usable colors
	unsigned int color[10];
 
	// Instantiation of the image dimensions
	int wide, high;
 
	// Instantiation of variables needed for the spiral.
	int degree, x, y;
	float radian;
 
	// Counter variables
	int imageNum, i, j, k;

The declaration of the main function, and declaration of the variables used for the program. A breakdown of important bits relevant to this tutorial is as follows.

  • FILE *out;
    gdImagePtr img;
  • Creates pointers for our output file and to our GD image.
  • char format[] = "output/%02d.png";
    char outfile[sizeof format+100];
  • This is where we define how the image files will be dynamically named. First, if you're writing to another folder (like we are, writing to the subfolder output), be sure that folder exists before you run your program. Next, depending on how many images you plan to generate, you may need to change the format. For the purpose of this tutorial, we will be creating 100 images. If you wish to do more, just change the value of %02d to the correct power of 10 for the amount of images you plan to create (%03d for 1000, %04d for 10000, etc.).
  • unsigned int color[10];
  • This is an array made to hold all the color values we plan on creating for the images. You can create many more, but for this purpose of this tutorial, we will be using 10.
/* Conditional statement for size of images based on arguments, defaulting to correct syntax in
	 * case of improper usage
	 */
	if(argc == 1)
	{
		wide = 800;
		high = 600;
		printf("Program run with no arguments\n");
		printf("Setting dimensions to default. W:800 x H:600\n");
	}
	else if(argc == 3)
	{
		wide = atoi(argv[1]);
		high = atoi(argv[2]);
		printf("Program run with two arguments\n");
		printf("Setting dimensions to W:%u x H:%u", wide, high);
	}
	else
	{
		printf("Syntax: gdgif [width] [height]\n");
		printf("If run with no arguments, the default dimensions are set to W:800 x H:600\n");
		exit(1);
	}

This if statement determines what to set the size of the images to, based on the arguments given at runtime. If the program is run with no additional arguments, it will set the images to a resolution of 800×600 by default. If run with two additional arguments, it will set the resolution to the first argument x the second argument. If run with any other number of arguments, it will print the correct syntax of the program, and then exit.

// Main loop of the program. Set to run as many times as the number of images you wish to create
	for(imageNum = 0; imageNum < 100; imageNum++)
	{
		// Creation of a new image
		img = gdImageCreate(wide, high);
 
		// Setting of the color values
		color[BLACK]                    = gdImageColorAllocate(img, 0x00, 0x00, 0x00);
		color[GRAY]                     = gdImageColorAllocate(img, 0x70, 0x70, 0x70);
		color[VIOLET]                   = gdImageColorAllocate(img, 0x8F, 0x00, 0xFF);
		color[INDIGO]                   = gdImageColorAllocate(img, 0x4B, 0x00, 0x82);
		color[BLUE]                     = gdImageColorAllocate(img, 0x00, 0x00, 0xFF);
		color[GREEN]                    = gdImageColorAllocate(img, 0x00, 0xFF, 0x00);
		color[YELLOW]                   = gdImageColorAllocate(img, 0xFF, 0xFF, 0x00);
		color[ORANGE]                   = gdImageColorAllocate(img, 0xFF, 0x7F, 0x00);
		color[RED]                      = gdImageColorAllocate(img, 0xFF, 0x00, 0x00);
		color[WHITE]                    = gdImageColorAllocate(img, 0xFF, 0xFF, 0xFF);
 
		/* Set the output file's name to the specified format, and name it based on the number of 
		 * times the main loop has run.
		 */
		sprintf(outfile, format, imageNum);
 
		/* Loop to generate a number of circles based on the number of images created with
		 * positions and colors set relevant to the number of times through the loop
		 */
		for(i = 0; i <= imageNum; i++)
		{
			degree = i * 10;
			radian = degree * (PI / 180);
			x = (wide / 2) + (i * 2) * sin(radian);
			y = (high / 2) + (i * 2) * cos(radian);
			gdImageFilledArc(img, x, y, (i + 3), (i + 3), 0, 360, color[i % 10], gdArc);
		}
 
		// Write the output file, and then write the image to the output file
		out = fopen(outfile, "wb");
		gdImagePngEx(img, out, -1);
 
		// Print the file being written
		printf("Writing: [%s]\n", outfile);
 
		// Clean up
		fclose(out);
		gdImageDestroy(img);
	}
 
	return 0;
}

Now we're starting to get into the real meat of the program. Here is where we begin the main loop that this program will run. It is set to execute equal to how many images we want to create (As stated by the “imageNum < 100” part of the first for loop). When the loop starts, we first call the gdImageCreate function, and create an image with the dimensions we chose earlier. Then, we have to create the colors we'll be using, with the gdImageColorAllocate function, which takes the pointer to the image we're working on, and then a hex color value (broken into three) as arguments. The last step before the second for loop (where the image generation actually happens) is to create a string to be used as the output name for this file.

The image creation loop runs a variable amount of times, depending on which image is currently being generated (one time for the first image, two times for the second, etc.). The first thing done in this loop are a few calculations to get the x and y values for the center of the circle being generated this time through the loop. After the program has these values, we finally draw something. We use the gdImageFilledArc function to draw a filled arc! This function accepts 9 arguments. First, like the gdImageColorAllocate function, we pass it the pointer of the image we're working on. We then tell it the center x and y values of the circle that were calculated in the previous four lines. We tell it the width and height of the circle (in this case, (i + 3) for both, to increase the size of the circle as the loop executes more times), the starting and stopping point of the arc ((0, 360) to make a full circle), the color to be used (color[i % 10], to give us a different color depending on how many times the loop has executed), and finally which type of arc to create (gdArc, in this case).

After the image has been completely generated, the next step is to write the image out. We first set the out pointer we used earlier to open a file with the filename calculated earlier in the loop. Next, we use the gdImagePngEx function to write the image we've been working with (img) to the file we just opened (out). As a bit of a debug message, we then have a printf statement which tells us which current file is being written. And finally, the last step is clean up before the loop starts again. We use fclose to close the file we opened, and gdImageDestroy to get rid of the image we've been working with so we can make a new one.

Execution

Once we have our program all written, the first step is to compile it (being sure to link to the GD library with -lgd).

gcc -o gdgif gdgif.c -lgd

Next, run the program. For demonstration's sake, I'm running it with the arguments 800 and 600 for width, although they're set as the default if the program is run with no arguments.

./gdgif 800 600

If everything worked right, you should see a bunch of messages with the output of the program saying that a total of 100 images were written to the output folder. Now that we have our images, the next step is to actually create a gif out of them. So first, cd into your output folder. Once there, do a quick ls to make sure you have 100 .png files, titled from 00.png to 99.png. And as long as they're all there, we'll use the convert tool to create our gif.

convert -loop 0 *.png loop.gif

This tells it to create an animated file, set to loop with a delay of 0 between loops, of all the .png files in this directory and save it as loop.gif. Once that is done, verify to be sure the loop.gif file is there. And if it is, you're on the final step. Enjoyment. :) If you followed this tutorial correctly, your loop.png file should look like this.

Now that you have your image, maybe you want to go back and make it your own. Maybe you already know the GD Image Library, or you're looking to experiment. Fortunately, it's pretty simple to adjust the program to create something different. All the image generation takes place in the loop between lines 93 and 100, so a little messing around there will give you a whole new image! Have fun!

References

While written for the PHP GD Library, this manual was very helpful in looking up the syntax for functions. All it takes is converting the function name from it's name in the PHP library to it's name in the C library (imagefilledarc for example in the PHP library is named gdImageFilledArc in the C library).

user/smeas/portfolio/hpc0project2.txt · Last modified: 2013/05/05 21:40 by smeas