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:
tucotuco.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%
This is the Hello World! of the GD library. Let's now
create a GIF file with 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.
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%
Try the script. 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.
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
Try
the script. 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.
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%
generates this:
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">
#!/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;
#
Logs. (Pattern matching). Sorting.
Java CGI (pipes).
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%
Try this combination. (Be patient.) 2. A simple Post'em system: an example/sketch of a term project.