#!/usr/bin/perl -w ############################################## # Create a png image a user defined function # on the fly with the GD.pm module. ############################################# use strict; use CGI; my $func = CGI->new->param("f"); unless ($func) { # --- print form asking user to define the function --- print "Content-type: text/html\n\n"; print "

Enter a function

\n"; } else { # -- create and output png image showing plot of the function -- my $img = PlotFunction::makeImage($func); print "Content-type: image/png\n\n"; binmode STDOUT; # needed for binary output on Windows print $img->png; } # ===================================== { package PlotFunction; use GD; use constant XPixBorder => 10; use constant YPixBorder => 10; use constant Epsilon => 1e-6; use constant XMax => 8.0 + Epsilon; use constant XMin => -8.0; use constant YMax => 1.5 + Epsilon; use constant YMin => -1.5; use constant XPixSize => 384; use constant YPixSize => 256; use constant DX => (XMax - XMin)/(XPixSize/2); use constant XConvert => XPixSize/(XMax - XMin); use constant YConvert => YPixSize/(YMax - YMin); our ($im, $white, $black, $grey, $darkBlue, $xpixpen, $ypixpen, $pencolor, $f ); our $initHasRun; sub init { return if $initHasRun; $initHasRun=1; # allocate new GD.pm Image. our $im = GD::Image->new(XPixSize+2*XPixBorder, YPixSize+2*YPixBorder); # allocate some colors. First allocated is background. our $white = $im->colorAllocate(255,255,255); our $black = $im->colorAllocate( 0, 0, 0); our $grey = $im->colorAllocate(172,172,172); our $darkBlue = $im->colorAllocate( 0, 0,128); # make the background transparent and the image interlaced. $im->transparent($white); $im->interlaced('true'); } # input: function f(x) to be plotted as a string, i.e. "sin(x)". sub makeImage { ($f) = @_; init(); # initialize globals for ($f) { # convert function s/exp/~~~/g; # from "exp(x)" form s/x/\$x/g; # to "exp($x)" s/~~~/exp/g; } $pencolor = $grey; # draw axes pendown(XMin,0); lineto(XMax,0); pendown(0,YMin); lineto(0,YMax); $pencolor = $black; # draw function my $x = XMin; my $y = f($x); my ($lastx, $lasty); pendown($x,$y); while ($x < XMax) { $lastx = $x; $lasty = $y; $x += DX; $y = f($x); lineto($x,$y); } $im->string(gdLargeFont, # label plot XPixBorder*2, YPixBorder*2, "f(x) = $func", $darkBlue); return $im; } # function to be plotted sub f { my ($x) = @_; return eval $f; } # convert x coords to pix sub xx { my ($x) = @_; return XPixBorder - (XMin-$x)*XConvert; } # convert x coords to pix sub yy { my ($y) = @_; return YPixBorder + (YMax-$y)*YConvert; } # input: (x,y) coords to place pen sub pendown { my ($x,$y) = @_; $xpixpen = xx($x); $ypixpen = yy($y); return; } # input: (x,y) coords # draw line from last pendown position to (x,y) sub lineto { our $im; my ($x, $y) = @_; my ($xpixnew, $ypixnew) = ( xx($x), yy($y) ); $im->line($xpixpen, $ypixpen, $xpixnew, $ypixnew, $pencolor); ($xpixpen, $ypixpen) = ($xpixnew, $ypixnew); return; } } # end PlotFunction package