Chapter 4. On-the-Fly Graphics with GD

The GD Perl module is a collection of methods and constants for reading, manipulating, and writing color GIF files. Although it is more limited in scope than the ImageMagick package, its size and speed make it well-suited for dynamically generating GIF graphics via CGI scripts. GD has become the de facto graphics manipulation module for Perl; other modules such as GIFgraph (described in Chapter 6) extend the GD toolkit to easily accommodate specific graphics tasks such as creating graphs and charts.

The GD Perl module is actually a port of Thomas Boutell’s gd graphics library, which is a collection of C routines created for manipulating GIFs for use in web applications. Early versions of the GD.pm module simply provided an interface to the gd library, but now GD has its own library that is optimized for use with Perl. This module was ported by Lincoln D. Stein, author of the CGI.pm modules.

This chapter starts with an overview and a sample CGI application that will implement a web-based “chess server” that interactively manipulates the pieces on a chess board. The remainder of the chapter is a more detailed description of the GD methods and constants, with additional information on more advanced topics such as using GD’s polygon manipulations functions.

GD Jumpstart

Scripts that use the GD module to create graphics generally have five parts, which perform the following functions: importing the GD package, creating the image, allocating colors in the image colormap, drawing on or manipulating the image, and writing the image to a file, pipe, or web browser. After you’ve installed the GD module, just follow these five steps:

  1. First you must import the GD methods into your script’s namespace with the use function. The command use GD will give you access to all of the methods and constants of the GD::Image, GD::Font, and GD::Polygon classes:

    GD::Image

    The Image class provides the means for reading, storing, and writing image data. It also implements a number of methods for getting information about and manipulating images.

    GD::Font

    The Font class implements a number of methods that store and provide information about fonts used for rendering text on images. Each of the fonts are effectively hard-coded; they are described as a number of bitmap matrices (similar to XBM files) that must be compiled as part of the source during installation on your system. GD provides a limited number of fonts; the GD::Font class exists to make it easier to expand font support in the future.

    GD::Polygon

    The Polygon class implements a number of methods for managing and manipulating polygons. A polygon object is a simple list of three or more vertices that define a two-dimensional shape.

  2. Create a new image. To make a new image, you can create a new, empty image object of a given width and height, or you can read an image from a file. To create an empty image, use the new method of the Image class, as in:

    # Create a new, empty 50 x 50 pixel image
    $image = new GD::Image(50, 50) || die "Couldn't create image";

    All image creation methods will return undef on failure. If the method succeeds, it will return a data structure containing the decoded GIF data for the image and store it in the given scalar value. This scalar can only contain one image at a time.

    GD supports three stored file formats: GIF, XBM (black and white X-bitmaps), and GD files. A GD format file is a file that has been written to a file using the gd( ) method. To read in the image data from a file, use newFromGif( ), newFrmXbom( ), or newFromGd( ), depending on the format of the stored file. Each of these methods takes a filehandle as an argument, so you must open the file before you read the image data from it:

    # Read an image from a GIF file
    open (GIFFILE, "beatniks.gif") || die "Couldn't open file!";
    $image = newFromGif GD::Image(\*GIFFILE) || die "Couldn't read GIF data!";
    close GIFFILE;
    
    # Read an image from an XBM file
    open (XBMFILE, "ginsburg.xbm") || die "Couldn't open file!";
    $image = newFromXbm GD::Image(\*XBMFILE) || die "Couldn't read XBM data!";
    close XBMFILE;
    
    # Read an image from a GD file
    open (GDFILE, "ferlinghetti.gd") || die "Couldn't open file!";
    $image = newFromGd GD::Image(\*GDFILE) || die "Couldn't read GD data!";
    close GDFILE;

    You are now ready to manipulate the image or write it to another file or to STDOUT.

  3. If you are going to be doing any drawing or manipulation of the image, you will need to get information about the colors available in the image. GD images support a maximum of 256 colors which are stored in the image’s color table. You may need to add new colors to an image’s color table, or you may need to get color indices of existing colors. Use the colorAllocate( ) method with a list of decimal red, green, and blue values to add a new color to the color table. This method returns the index of the color in the color table, which you should store for use with drawing methods requiring a color index:

    $red = $image->colorAllocate(255, 0, 0);
    $grey2 = $image->colorAllocate(51, 51, 51);

    Use colorNearest( ) and colorExact( ) to determine the color index of a color already in the color table. Use colorsTotal( ) to find out how many colors are currently allocated.

  4. To draw on an image, use one of the graphics primitives. For example, to draw a 100 × 100 rectangle with purple lines in the upper left-hand corner of an image, use:

    $purple = $image->colorAllocate(255, 0, 255);
    $image->rectangle(0, 0, 100, 100, $purple);

    It is possible to use any of the drawing primitives with specially defined brushes by specifying the gdBrushed constant instead of a color. You can also fill areas with a tiled pattern with the gdTiled constant.

    GD provides a special class, GD::Polygon, for managing information about polygons. First create a new polygon object with new( ), add points to it with the addPt( ) method, then draw it to an image with the polygon( ) drawing primitive. To draw the same filled purple rectangle above as a polygon, use:

    # Create a new polygon object
    my $polygon = new GD::Polygon;
    
    # Add each of the polygon's vertices
    $polygon->addPt(0,0);
    $polygon->addPt(0,100);
    $polygon->addPt(100,100);
    $polygon->addPt(100,0);
    
    # Allocate the color purple in the image.
    # Note that if this is the first color allocated in $image, 
    # it will become the background color.
    #
    $purple = $image->colorAllocate(255, 0, 255);
    
    # Now draw the polygon in purple on the image
    $image->polygon($polygon, $purple);
  5. When you are finished manipulating the image, you can write it to a file or to STDOUT. To write to a file, you must first open the file for writing with the open command. If you are working on a platform that makes a distinction between text and binary files (such as Windows 95/NT), be sure that you are writing in binary mode by calling the binmode( ) method first. To write the data as a GIF file, call the gif( ) method which returns the image data in the GIF format:

    open OUTFILE, ">output.gif";         # Open the file for writing
    binmode OUTFILE;                     # Make sure we're in binary mode
    print OUTFILE $image->gif;           # Print GIF data to the file
    close OUTFILE;

    You can also write to a GD format file with the gd( ) method. Note that you can read from XBM files but you cannot write to them; you’ll need an external utility if (for some reason) you want to do that. Also note that you cannot use GD manipulation routines directly on data generated by a gif( ) or gd( ) method call; all method calls should be made on the original GD::Image object.

    GD images can also be handed off to other packages such as PerlMagick or GIFgraph for additional manipulation. See Chapter 6 for this discussion.

Get Programming Web Graphics with Perl and GNU Softwar now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.