Documentation for the GD library can be found on what's currently known as the Stein Laboratory
GD allows you to create color drawings using a number of primitives and emit drawings as GIF files. There are basically four steps to creating an image using the GD.pm library:
This is the Hello World! of the GD library. Let's now create a GIF file withtucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/htdocs tucotuco.cs.indiana.edu% vi one tucotuco.cs.indiana.edu% cat one #!/usr/bin/perl use GD; # create a new image $im = new GD::Image(100,100); # allocate some colors $white = $im->colorAllocate(255,255,255); $black = $im->colorAllocate(0,0,0); $red = $im->colorAllocate(255,0,0); $blue = $im->colorAllocate(0,0,255); # make the background transparent and interlaced $im->transparent($white); $im->interlaced('true'); # Put a black frame around the picture $im->rectangle(0,0,99,99,$black); # Draw a blue oval $im->arc(50,50,95,75,0,360,$blue); # And fill it with red $im->fill(50,50,$red); # make sure we are writing to a binary stream binmode STDOUT; # Convert the image to GIF and print it on standard output print $im->gif; tucotuco.cs.indiana.edu%
one
and place it where it
can be accessed from the web.
As you can see the file is in GIF format. We have placed it in ourtucotuco.cs.indiana.edu% ./one > one.gif tucotuco.cs.indiana.edu% file one.gif one.gif: GIF file, v89 tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/htdocs tucotuco.cs.indiana.edu% ls -l one.gif -rw-r--r-- 1 dgerman students 623 Oct 5 23:17 one.gif tucotuco.cs.indiana.edu%
DocumentRoot
so it can be accessed
from the web. In fact you can find it here. We can also include it here (as you can see, below) with the following HTML code:
and there you have it:<img src="http://tucotuco.cs.indiana.edu:19800/one.gif">
But this, of course, is a static file.
We can create an image on the fly if we eliminate the intermediary
file that we stored in our DocumentRoot
. In other words
if we send the file to the browser as soon as we are done creating the
image. So let's try it.
But if you try to access the script now you would obtain:tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/htdocs tucotuco.cs.indiana.edu% ls -l one -rwx------ 1 dgerman students 809 Oct 5 23:13 one tucotuco.cs.indiana.edu% cp one ../cgi-bin/one tucotuco.cs.indiana.edu% cd ../cgi-bin tucotuco.cs.indiana.edu% ls -l one -rwx------ 1 dgerman students 809 Oct 5 23:32 one tucotuco.cs.indiana.edu%
where the output was edited for readability.tucotuco.cs.indiana.edu% tail -1 ../logs/error_log [Mon Oct 5 23:34:06 1998] [error] malformed header from ... ... script. Bad header=GIF89ad: /u/dgerman/httpd/cgi-bin/one tucotuco.cs.indiana.edu%
We remember that one a script is written a lot of responsibility is taken, the server simply passes the data to the script and then waits for its output which it then sends to the client browser.
That means that we need to add the MIME type for the GIF file if we want to offer it over the web because nobody is going to do it for us.
The following code then, differs in exactly one place from the
program that created the GIF file in the DocumentRoot
directory. The line is underlined.
Try the script.tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/cgi-bin tucotuco.cs.indiana.edu% vi one tucotuco.cs.indiana.edu% cat one #!/usr/bin/perl use GD; # create a new image $im = new GD::Image(100,100); # allocate some colors $white = $im->colorAllocate(255,255,255); $black = $im->colorAllocate(0,0,0); $red = $im->colorAllocate(255,0,0); $blue = $im->colorAllocate(0,0,255); # make the background transparent and interlaced $im->transparent($white); $im->interlaced('true'); # Put a black frame around the picture $im->rectangle(0,0,99,99,$black); # Draw a blue oval $im->arc(50,50,95,75,0,360,$blue); # And fill it with red $im->fill(50,50,$red); # make sure we are writing to a binary stream binmode STDOUT; # Convert the image to GIF and print it on standard output print qq{Content-type: image/gif\n\n}; # first things first print $im->gif; tucotuco.cs.indiana.edu%
It generates a new image (one and the same) every time it is being accessed.
Now we know how to generate images on the fly.
Let's make them more time sensitive.
Let's make a clock.
First, a digital clock.
Try the script.tucotuco.cs.indiana.edu% ls -ld lecture* drwx------ 2 dgerman students 512 Sep 10 01:15 lecture4 drwxr-xr-x 2 dgerman students 512 Sep 27 23:45 lecture9 tucotuco.cs.indiana.edu% mkdir lecture10 tucotuco.cs.indiana.edu% cd lecture10 tucotuco.cs.indiana.edu% vi dclock tucotuco.cs.indiana.edu% cat dclock #!/usr/bin/perl use GD; print "Content-type: image/gif\n\n"; ($seconds, $minutes, $hour) = localtime(time); if ($hour > 12) { $hour -= 12; $ampm = "pm"; } else { $ampm = "am"; } if ($hour == 0) { $hour = 12; } $time = sprintf("%02d:%02d:%02d %s", $hour, $minutes, $seconds, $ampm); $time_length = length($time); $font_length = 8; $font_height = 16; $x = $font_length * $time_length; $y = $font_height; $image = new GD::Image($x, $y); $black = $image->colorAllocate(0, 0, 0); $yellow = $image->colorAllocate(255, 255, 0); $image->string(gdLargeFont, 0, 0, $time, $yellow); print $image->gif; exit(0); tucotuco.cs.indiana.edu% ls -l dclock -rw-r--r-- 1 dgerman students 623 Oct 6 00:16 dclock tucotuco.cs.indiana.edu% chmod 700 dclock tucotuco.cs.indiana.edu% ls -l dclock -rwx------ 1 dgerman students 623 Oct 6 00:16 dclock
Well, there's really no reason not to include it here, after all, so let's just do it:
That is:<img src="http://tucotuco.cs.indiana.edu:19800/cgi-bin/lecture10/dclock">
Note though, that the time is the time on the server, and that the image is a snapshot.
Now let's try an analog clock.
As you can see here the only trouble here is with the coordinates. The image needs to be reflected for the coordinates to match. (And we also need to translate it to keep the drawing within positive range and to scale it so that we can tell the minute hand from the hour hand - the hour hand is shorter).tucotuco.cs.indiana.edu% vi aclock tucotuco.cs.indiana.edu% cat aclock #!/usr/bin/perl use GD; print "Content-type: image/gif\n\n"; ($seconds, $minutes, $hour) = localtime(time); $x = $y = 100; $R = $x / 2; $twopi = 2 * 3.141592; $dhx = $R * sin($hour / 12 * $twopi); # [1] $dhy = $R * cos($hour / 12 * $twopi); # [2] $dmx = $R * sin($minutes / 60 * $twopi); $dmy = $R * cos($minutes / 60 * $twopi); $dhy = - $dhy; # mirror $dhy *= 0.66; $dhx *= 0.66; # scale $dhx += $R; $dhy += $R; # translate $ox = $R; $oy = $R; # translate origin $dmy = - $dmy; # mirror $dmx += $R; $dmy += $R; # translate $image = new GD::Image($x, $y); $black = $image->colorAllocate(0, 0, 0); $yellow = $image->colorAllocate(255, 255, 0); $image->line($ox, $oy, int($dmx), int($dmy), $yellow); $image->line($ox, $oy, int($dhx), int($dhy), $yellow); $image->arc($R, $R, 2 * $R, 2 * $R, 0, 360, $yellow); print $image->gif; exit(0); tucotuco.cs.indiana.edu%
gives us<img src="http://tucotuco.cs.indiana.edu:19800/cgi-bin/lecture10/aclock">
This should be as above.
Question: if it isn't, how far apart can they be, and why?
Also, do you see a minor problem with the code?
You should.
The lines marked with [1] and [2] should be changed to:
for the hour hand to move smoothly.$add = 0; # $add = $minutes / 60 / 12; $dhx = $R * sin(($hour / 12 + $add) * $twopi); $dhy = $R * cos(($hour / 12 + $add) * $twopi);
Before that let's quickly look at colors.
generates this:tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/cgi-bin/lecture10 tucotuco.cs.indiana.edu% vi colors tucotuco.cs.indiana.edu% cat colors #!/usr/bin/perl use GD; print "Content-type: image/gif\n\n"; $x = $y = 100; $image = new GD::Image($x, $y); srand(time); for ($i = 0; $i < 255; $i++) { $color[$i] = $image->colorAllocate( int(rand(255)), int(rand(255)), int(rand(255)) ); } for ($i = 0; $i < $x; $i++) { for ($j = 0; $j < $y; $j++) { $image->setPixel($i, $j, $color[int(rand(255))]); } } print $image->gif; exit(0); tucotuco.cs.indiana.edu%
You see that you have access to a wide range of colours and possibilities.
It counts the number of times that page was loaded.
It needs to count all accesses, and to store them.
The source of data is a file.
Now we have a place where we will keep the actual counter or counters.tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd tucotuco.cs.indiana.edu% mkdir datafiles tucotuco.cs.indiana.edu% cd datafiles tucotuco.cs.indiana.edu% mkdir counters tucotuco.cs.indiana.edu% cd counters tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/datafiles/counters tucotuco.cs.indiana.edu% vi c1 tucotuco.cs.indiana.edu% vi c1.semaphore tucotuco.cs.indiana.edu% ls -l c1* -rw-r--r-- 1 dgerman students 2 Oct 6 14:00 c1 -rw-r--r-- 1 dgerman students 0 Oct 6 14:00 c1.semaphore tucotuco.cs.indiana.edu% cat c1* 0 tucotuco.cs.indiana.edu
And here it is.#!/usr/bin/perl use GD; print "Content-type: image/gif\n\n"; $location = "/u/dgerman/httpd/datafiles/counters"; open (U, "$location/c1.semaphore"); flock(U, 2); open (M, "$location/c1"); $x =; close(M); $x += 1; open (M, ">$location/c1"); print M $x, "\n"; close(M); flock(U, 8); $counter = sprintf(" %s ", $x); $counter_length = length($counter); $font_length = 8; $font_height = 16; $x = $font_length * $counter_length; $y = $font_height; $image = new GD::Image($x, $y); $white = $image->colorAllocate(255, 255, 255); $blue = $image->colorAllocate(0, 0, 255); $image->transparent($white); $image->string(gdLargeFont, 0, 0, $counter, $blue); print $image->gif;
It has been accessed
times.
Note that you can set/reset it by changing the $location/c1 file.
is the output of this script, with input University and 3.2 as the average. It produces this image tag:
The source of data is the QUERY_STRING (basically) although we get to the values with the $query->param(...) method.<img src="http://www.best.indiana.edu/cgi-bin/norms/shape?distri=17:0:0:4:7:7:8:23:33:34:77:104:115:217:260:269:424:473:647:862:934:1107:1204:1700:1918:1981:2346:2374:2880:2994:3037:2925:2449:2481:2179:1752:1409:1021:802:416:392&avera=3.2">
Logs. (Pattern matching).#!/usr/bin/perl use GD; use CGI; $query = new CGI; $x0 = 5; $y0 = 5; $xmax = 350; $ymax = 110; $im = new GD::Image($xmax+1, $ymax+1) || die; $white = $im->colorAllocate(255, 255, 255); $lightblue = $im->colorAllocate(190, 190, 255); $blue = $im->colorAllocate( 0, 0, 255); $grey = $im->colorAllocate(200, 200, 200); $yellow = $im->colorAllocate(255, 255, 0); $im->transparent($white); $im->interlaced('true'); $im->filledRectangle($x0, $y0, $x0 + 8 * 41, $y0 + 100, $white); $im->rectangle($x0, $y0-1, $x0 + 8 * 41+1, $y0 + 100 + 1, $blue); $distri = $query->param('distri'); @bins = split(/:/, $distri); $avera = $query->param('avera'); $max = -1; $sum = 0; foreach $val (@bins) { $sum += $val; $max = $val if ($max <= $val); } for ($i=0, $lim=0.05; $i<= 40; $i++, $lim += 0.1) { # $percent = $i / 40 * 100; $percent = 0; if ($max > 0) { $percent = 100 * $bins[$i] / (1.2 * $max); } if (($lim > $avera) && ($lim - 0.1 <= $avera)) { $im->filledRectangle($x0 + $i * 8 + 1, 100 - $percent + $y0, $x0 + ($i + 1) * 8, $y0 + 100, $lightblue); } else { $im->filledRectangle($x0 + $i * 8 + 1, 100 - $percent + $y0, $x0 + ($i + 1) * 8, $y0 + 100, $blue); } if (100 - $percent > 0) { if (($lim > $avera) && ($lim - 0.1 <= $avera)) { $im->filledRectangle($x0 + $i * 8 + 1, $y0, $x0 + ($i + 1) * 8, $y0 + 100 - $percent, $yellow); } else { $im->filledRectangle($x0 + $i * 8 + 1, $y0, $x0 + ($i + 1) * 8, $y0 + 100 - $percent, $grey); } } } # print "Content-type: text/html\n\nText"; exit; print "Content-type: image/gif\n\n"; print $im->gif; #
Sorting.
Java CGI (pipes).
Try this combination. (Be patient.)tucotuco.cs.indiana.edu% pwd /nfs/paca/home/user2/dgerman/httpd/cgi-bin/lecture10 tucotuco.cs.indiana.edu% vi jCGI tucotuco.cs.indiana.edu% cat jCGI #!/usr/bin/perl open (AB, "| java myCGIscript"); while (<STDIN>) { print AB; } close(AB); tucotuco.cs.indiana.edu%vi myCGIscript.java tucotuco.cs.indiana.edu% cat myCGIscript.java public class myCGIscript { public static void main (String[] args) { System.out.println("Content-type: text/html\n\n" + "Hello, CGI world! Java, Java."); } } tucotuco.cs.indiana.edu% javac myCGIscript.java tucotuco.cs.indiana.edu% ./jCGI ^D Content-type: text/html Hello, CGI world! Java, Java. tucotuco.cs.indiana.edu%
2. A simple Post'em system: an example/sketch of a term project.