GD in Perl
Home Up thttpd Web Server Cherokee web CRON and SSMTP Samba Velleman K8055 Perl Module GD in Perl Slugos-native

 

CGI, Perl, GD and GD::Graph

I want to plot graphs of measurements made by a k8055 I/O board. The Perl language is primarily intended for text processing and has no built-in graphics functionality. Graphics can be added by installing additional modules.

  • GD.pm is an interface library for perl, it allows a perl script to use functions from GD. 
  • GD::Text.pm adds text drawing functions
  • GD::Graph.pm draws charts and graphs from data supplied in arrays.
  • GD is a library of graphics functions. Graphics are drawn into a buffer, which is usually then stored as a file. The file may be in "GIF" format or if LibPNG is available the file may be in "PNG" format.
  • LibPNG is a library to enable the loading and saving of graphics in the PNG (Portable Network Graphic) format. LibPNG Reqires zlib.
  • Zlib is a data compression library.
  • Freetype is an open source implementation of Truetype fonts. GD will use it if it is installed.

I was disappointed to find that GD and GD.pm are not included in the current openslug packages. I was further disappointed to find that GD.pm would not install. The install failed due to some files being reported missing.

Before you can install the Perl GD module you will need to carry out the steps in Perl Module

Also note that to perform this installation I had the entire "slugos-native" package installed.

I downloaded and installed the following packages:

  1. zlib-1.2.3
  2. libpng-1.2.15
  3. freetype-2.2.1
  4. gd-2.0.33

Installing a source package typically consisted of six steps:

  1. Download the package in "tar.gz" form using wget
  2. unpack the package using tar -xzf <filename>
  3. Find and run the "Configure" script
  4. run make
  5. run make test
  6. run make install

I made some changes to the perl install.

Now you've replaced the missing files and fixed the toolchain you can go ahead and install the perl modules:

  1. GD
  2. GD::Text
  3. GD::Graph
The GD::Graph examples create files in the samples directory.

If you want to see a graph in your browser there is a crude example of a CGI program returning a graph in http://tandem.bu.edu/classes/2005s/papers/perlgdgraph.pdf and I've patched it a bit to run on my slug: gd_example.pl. It uses a slightly dubious way to output the graph: it writes the graph to a file then returns a reference to the file. The file always has the same name. This technique will cause serious problems in a real web application* but it's just about tolerable for a demo or home LAN based tool.

It's set up to create an image in /var/www/images so the images directory must be writable. I used chmod 777 /var/www/images Also it assumes the server's domain is 192.168.3.253. Edit this to match your system. I've added the CGI::Carp module so you can see errors easily.

* For clarification: the problem is that each time you visit the site a new graphics file is generated replacing the old one, and if you have simultaneous users then they will often see the "wrong" file. If file locking isn't implemented then they may even see corrupted downloads. Normally the simplest way round it is to build and return an image URL containing the parameters of the graph then have the image generated by a script in response to the parameters. In the case of a data graph this could easily create an excessively large URL though, and directly passing the data between scripts could require session management.

I suppose an intermediate fix might be to embed a timestamp in the image filename, and also clean up old images.

Perl and GD the hard way

It is possible to compile Perl from source on the slug, however it is demanding, and can only be done by adding a swapfile. I carried out the following steps:

  1. Booted my PC with a "GParted" CD.
  2. Made up a small external hard drive using an old 6Gb drive and a Newlink case.
  3. I used GParted to copy the SDA1 and SDA2 of my USB stick openslug onto the hard drive, at the same time resizing them and leaving 512Mb free at the end. I converted the free part into a swap partition.
  4. Booted the slug with no drive attached, added the hard drive and ran turnup disk /dev/sda1 to switch over to the disk and rebooted. Note that this step was unnessecery. All my test systems have the boot on the first partition so all I have to do is shut down, change drive, restart.
  5. I used mkswap to convert /dev/sda3 into a swap partition for the slug
  6. I added a line to /etc/fstab to say that sda3 was swap
  7. I ran swapon -a to activate the swap partition.

I now had enough memory to build perl from source. After the build I did make test and it failed one test, I still do not know if this is important. At the end I was able to install GD.pm and run a simple test script.

I was left with a somewhat broken openslug in which the installed perl was out of step with the package manager, but at least GD worked.

Complications with a CGI script using GD

The process of returning dynamic graphics is complicated as the graphics will almost certainly be a part of a dynamically generated page. Unfortunately the page and graphic will be transferred as separate operations. This means one of several workarounds will be required to get the graphic to show the correct content. 

  1. Make the graphic generator self contained. Example: a web counter.

    This really only works for extremely simple applications where the reader does not interact with the script at all.
  2. Pass all the data needed to generate the graphic as parameters in the URL

    This method should work well when the amount of data passed is relatively small, for example a 12 column bar chart. Unfortunately there's a limit to how much data you can pass this way.
  3. Pass parameters so the script that generates the graphic can look up the required data.

    This should work better than the previous method for larger data sets.
  4. Derive the data from the referrer information which should contain the URL of the page, and therefore any parameters that were in the page's URL

    This is unreliable, it would only work for "GET" type forms, not "POST" and some browsers would break it.
  5. Pass a database query in the URL so the graphics script can perform the query and make it into graphics.

    Warning this risks opening a big security hole. Don't go there. If you do you'll have to validate the query carefully to make sure its safe or you risk a hacker writing a special url containing a database command.
  6. Set a per-session cookie on the browser or use a session URL, use the session to pass data between scripts

    This is the preferred method, though it's probably more work than passing data in the URL.
  7. Have the script that generates the HTML also generate the graphics as image files with fixed names

    This is a quick, dirty and somewhat unsound way to generate CGI graphics that will probably work well on a very limited number of applications. If only one user browses the page things will probably work, although the graphics may get cached by the browser preventing updates. As soon as two users browse the site you risk a race condition with one user seeing the other's graphics.

    This method does have it's uses. One perfectly valid application would be changing the "skin" of a site, where a script would recreate all the buttons and banners for a site. In this case the script might not even be cgi, it could be in a cron job set to change the site's appearance at certain dates, and the web server would not have to support cgi. The script might not be running on the web server, you could have a slug generate a graph and write it to your webspace on your ISP's server via FTP.
  8. Have the script that generates the HTML also generate the graphics as image files with changing filenames

    This is probably a very bad idea. While it fixes the multiple user issue it opens up the problem of cleaning up unwanted graphics files. If the files can build up this enables a denial of service attack where the script is called repeatedly to fill up local storage.