N342 Dynamic Server Graphics |
Modified: |
Graphics generated from dynamic data or user input is an effective means of communicating. There are two main approaches:
- server-side using standard programming language such as ASP, Perl, C, etc. and graphics package such as gd (roll your own) or gnuplot (plotting library)
- generate graphics files (e.g. GIF/JPEG etc.) understood by most browsers
- generate graphics language (e.g. SVG/VML etc.) that require a browser plugin
- client-side
- HTML - no graphics
- Javascript - minimal graphics
- Java/Flash - graphics through programming
Most commonly, graphic files are generated on the server in some standard format and sent to the browser for rendering. The standard format of an image file is:
- a content-type header,
- blank line
- binary graphic data in appropriate format
For example, the image at right would be sent to the browser as:
Content-type: image/png
‰PNG
IHDR @ FMY )PLTE € @ €@ €€@ € ` `€`€ € @€0`€€` @@@@€ €€` €``€`€ ` @€` ` ` € € €` €``` @@ @€`€ `€``€€€€@ € €€€ €€` €`€ €`@ @@€€`€€ € `` € € € € €@ €@€€`€`€€ €@ @ ` p €T&s tIDATxœٺ‚0 „ ”–.I…™ 4Oq!" A A A 4ֵw sk @‘V@ K `tŸ/BS{j_ Z )R‹6’ D{ Qš%r*7; s€EC*/bб› 20xE‰ѥs9T ~ H zŠM l #W4 N4) 0‹ƒ^z X€?~[* Hœx @†#cz-d‚ n=!5Ž{}f M ~$ #} †!C' y ˜…7z¼ 8 @#c̲o}; 2'9č &F '-ˆ ( = – ߫Gb‰ 6 @ 0k…qQYl‡! ȫ‰ Ž% 8 ” ‘ ‘24 ? {QI– Ž‹=-&D @Ž €:9u h4< ; 1L p h - –,B ‡ q €cL€‚š .[qj ` xZŠ\€_Ej"B€Ž<X šˆ=…$… X‰ PJœ PP JV3D €‡5 3 Ph €B 2 Ot ϣ qG€ @mCkˆ 9 P C \ ‰ †ž ` 0' M †e%W!k €^5 € Gb=S5 ]X f€_nf y x-† #-„CMD/YSƒ „ P( j@€e
C 0 * @o Ov ™Gz €BǨ ‰ X:OD•G'ƒ5o' €”u Œ* g€…
j"AU8 Zˆ vD €u] 9OV•G1Ÿ ƒt& €2 œ‹W9E s9@œ Pp €5Y €B
(4 ™V † @a MC3O'ر٣ ˏG €z 0'-€VX
(:k4Pr<t @+ƒKNZ cF’“ڏ‹ P" K Ph " f
7 P“9Bh < )\Od@€ 9)‹ €? `r sy" 3< †B)(j‰cg p y"M ϶ ˜:O)6ºi iŠx6 g P— ,<Š r X_ €Нx 0
C< J 6 0.><” 5‘%>"} €‰Z ™ `%%G€—‹ oI k"‰‰(6\k $^O$Y I]Oq _j/k^' €–AMdY 3P;ٹ ֯' €4e'b P! “ S œ&@9 rs;@œ Ph˜ ` ` Ph @'@d 0 k D vš ?‰ ^{ ˜‰„€c %ƒvMq _R} b &B h1:)@œšk"1 HR&rG€Uƒ7 d/m ^œ R s ] G7 HJ ^ iZ€FčC €Bt }‘*zM u ‚2@Y XŽš’‰œ"Z$d ;k" €fmC˜CŒ!„nM `H&r7€ ƒnMD 9 ǡM › x< B Ž …†. l C d4#O[ C č šŽ —0 u[ † Œ CŰF| ’(ˆ 9;0l p ˜4” nv < )5? —A3†Bn UF —EqR 5 … @‘ ‚ ‚ŒB.N~5uGLŽ8TžˆPďk2 qIm‚ң—Y( 19P
gƒ_še-‰`Š]… U“ › 5 B|qŽƒ cy"z 4 Z q‚ D vaI@ձDhŽ: A A A U L.$~ IENDB`‚
gd - The gd library can produce png files that most current browsers can render. The gd library is callable from C programs allowing incorporation of dynamically generated graphics into CGI programs. The following is a simple example of a program that draws a white diagonal line on a black background. Note that HTTP header files are included to inform the browser as to the format of the image file.
Further information - The source for the gd library is at http://www.boutell.com/gd/
along with details of its use. The following example includes a zip file
with all the necessary files to use the gd library from C or C++.
| simplegd.c
#include "gd.h"
int main() { gdImagePtr im; /* Declare the image */ int white, black; /* Declare color indexes */ im = gdImageCreate(64, 64); /* Allocate the image: 64 pixels across by 64 pixels tall */ black = gdImageColorAllocate(im, 0, 0, 0);
/* Allocate the color black (red, green and blue all minimum).
gdImageLine(im, 0, 0, 63, 63, white);
/* Draw a line from the upper left to the lower right,
printf( "Content-type: image/png\r\n\r\n"); /* Print HTTP header */ _setmode( _fileno( stdout ), _O_BINARY );
/* Setmode for stdout to binary, necessary for
gdImagePng(im, stdout); /* Output the image to stdout in PNG format. */ gdImageDestroy(im);
/* Destroy the image in memory. */
Exercise -1 - gd
Command line compiling, linking and running simplegd.cpp
URL - http://localhost/Graphics/gd.exe assuming gd.exe in virtual directory Graphics. ![]() |
Environment.cpp
#include <iostream.h>
void main(int argc, char *args[], char *envp[]) {
cout << "Content-type: text/html\n\n";
for (int i=0; envp[i] != NULL; i++)
cout << envp[i] << "<br>\n";
}
|
Pipe.pl
open(FILE,"environment.exe |");
while ( <FILE> ) {
print;
}
|
Fly - A simple graphics language called Fly has been implemented using an earlier version of the gd library, hence the use of GIF encoding of graphics files rather the PNG. The language name comes from on the fly graphics. The Fly language programs can be run from the command prompt to produce a GIF file or a. A more interesting application for us is to wrap a Fly program inside of a Perl program to produce a CGI program that generates graphics on the fly back to a browser.
The Perl example below creates a GIF graphic, writes the HTTP header Content-type: image/gif and the binary GIF to standard output. The browser receives the header and interprets the following data as a GIF image. Fly is not very useful as a CGI directly since it does not have any control or data structures. The Perl program serves as a wrapper for the Fly program and can do the program control. The Perl program first writes all the Fly statements to a file named c:\temp\fly.$$ then invokes the Fly interpreter on that file using the statement open(FOO,"$flyprog -q -i $infile |"); which pipes the Fly output to the file FOO. Because DOS (Win95, etc.) automatically converts \n to \r\n all \r\n in the FOO file must be converted back to \n before sending to the browser.
Further information - The complete Fly can be downloaded
from http://www.unimelb.edu.au/fly/
. If you plan to get very serious about producing on the fly graphics either
use the gd library in C++ or get the GD.pm for Perl.
Fly in Perl cgiGIF.pl
$flyprog = "c:\\Fly\\fly";
$infile = "c:\\temp\\fly.$$";
open(FLY,"> $infile");
# Output the following to the FLY c:\\temp\\fly.$$ file
print FLY << "End";
new
size 256,256
fill 1,1,255,255,255
circle 128,128,180,0,0,0
fill 128,128,255,255,0
arc 128,128,120,120,0,180,0,0,0
circle 96,96,10,0,0,0
circle 160,96,10,0,0,0
fill 96,96,0,0,0
fill 160,96,0,0,0
string 0,0,0,10,240,giant,Hello, World!
string 0,0,0,100,10,medium,Don't worry, be Happy!
End
close(FLY);
open(FOO,"$flyprog -q -i $infile |");# Execute FLY on above to
# capture graphics to FOO
binmode(STDOUT);
binmode(FOO);
print "Content-type: image/gif\n\n";
while ( $status = read(FOO, $data, 4096)){# Write graphics file
$_ = $data; # back to client
s/\r\n/"\n"/eg; # after \r\n to \n
print;
}
close(FOO);
|
URL - http://localhost/Graphics/cgiGIF.pl
Assumptions:
DOS.Fly program - Reads dos.fly program and writes to hello.gif c:> fly -q -o hello.gif < dos.fly new
|
| xy Data Plotter
#include "gd.h"
int MINX=0, MINY=0, MAXX=250, MAXY=150;
// Default graphic size
void SetSize(int minx, int miny, int maxx, int maxy) {
// Set size of graphics in pixels
void SetWindowViewport() {
// Determine constants for
double xWorldToScreen(double x){
// Transform x World to x Screen
double yWorldToScreen(double y){
// Transform y World to y Screen
void SetViewPort(int x1, int y1, int x2, int y2){
// Define screen viewport
void SetWindow(double x1, double y1, double x2, double y2) {// Define
real-world window
void ShowLine(double x1, double y1, double x2, double y2){
// Display line on device
void initializeGraphics() {
green = gdImageColorAllocate(im, 0, 255, 255);
/* Allocate the color green
void close() {
_setmode( _fileno( stdout ), _O_BINARY );
/* Setmode for stdout to binary, necessary for
gdImagePng(im, stdout); /* Output the image to stdout in PNG format. */ gdImageDestroy(im);
/* Destroy the image in memory. */
void xyPlot(double x[], double y[], int nValues, char xaxis[], char
yaxis[]) {
xmin=x[0]; xmax=xmin; ymin=y[0]; ymax=ymin;
xinterval = fabs(xmax-xmin)/(NINTERVALS-1);
initializeGraphics(); SetWindow(xmin,ymin,xmax,ymax);
// Graph region in world coordinates
for (i=0; i<nValues-1; i++)
ShowLine(xmin,ymax,xmin,ymin);
SetWindow(xmin,ymin,xmax,ymin+yinterval);
for (i=0; i<NINTERVALS; i++) {
// X tics
SetWindow(xmin,ymin,xmin+xinterval,ymax);
strcpy((char *) buffer, xaxis);
void main() {
xyPlot(x,y, 12, "X-Axis", "Y-Axis");
|
|||
Use - A simple xy plot library xy.lib can be used to generate xy data plots by calling the xyPlot function. In the current version, the main function must be written to specify:
void xyPlot(double x[], double y[], int nValues, char xaxis[], char yaxis[]); Example - To run the above example:
Hints
SetSize(0, 0, 250, 150);
|
test.cpp
#include <stdlib.h>
void xyPlot(double x[], double y[], int nValues,
char xaxis[], char yaxis[]);
void SetSize(int, int, int, int);
void main(int argc, char *args[]) {
double x[100];
double y[100];
SetSize(0,0,200,200);
for (int i=1; i<argc; i++) {
y[i-1]=atof(args[i]);
x[i-1]=i;
}
xyPlot(x,y, argc-1, "X", "Y");
}
|
http://localhost/Graphics/xyplot.exe?15+27+5+7+-8
|
Example Form Data - The following uses the xy.lib to take
y-axis
data
from a form text box and plot.
test.cpp
#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
void xyPlot(double x[], double y[], int nValues,
char xaxis[], char yaxis[]);
void SetSize(int, int, int, int);
void main() {
double x[256];
double y[256];
float a;
int n=0, length;
char input[4096], remainder[4096];
sscanf( getenv("CONTENT_LENGTH"), "%d", &length);
for (int i=0; i<length; i++) cin >> input[i];
input[length]='\0';
sscanf(input, "userinput=%s", remainder);
n=0;
while(sscanf(remainder,"%f+%s",&a,remainder) == 2) {
y[n]=a;
x[n]=n;
n++;
}
sscanf(remainder,"%f",&a);
y[n]=a;
x[n]=n;
n++;
SetSize(0,0,200,200);
xyPlot(x, y, n, "X", "Y");
}
|
xyplot.htm
<form method=post action="http://localhost/Graphics/xyplot.exe">
Browser
http://localhost/Graphics/xyplot.exe
|
<img src="sine.pl">
sine.pl for Unix #!/usr/bin/perl $GNUPLOT = '/usr/bin/gnuplot'; $|=1; # no buffering binmode STDOUT; # binary output print "Content-type: image/png\n\n"; open(GRAPH,"| $GNUPLOT") || die; print GRAPH <<END; set terminal png set size 0.5, 0.5 plot [-16:16] sin(x) END close (GRAPH); |
![]() |
Note that the sine.pl must be in the Web server's cgi-bin and executeable.
Microsoft
The above example should work on most Web servers, it does not on Microsoft IIS, the problem seems to be with how IIS and Perl handle standard input and output. The gnuplot version used should NOT be the standard one with the graphical interface but the one compiled for DOS, a recent version is gp400DJ2.
The following is a less satisfactory work-around in which:
The sine.gp file contains the gnuplot commands.
The HTML to execute the Perl would be the same:
<img src="sine.pl">
sine.pl for Microsoft
$GNUPLOT = 'C:\\gp400DJ2\\gnuplot.exe';
$|=1; # no buffering
# execute gnuplot, read sine.gp for commands
open(GRAPH,"|$GNUPLOT sine.gp") || die "Can't run gnuplot: $!\n";
close (GRAPH);
# input graphics file
open( GRAPHFILE, "< sine.png" ) || die( "Can't open sine.png: $!\n" );
print "Content-type: image/png\r\n\r\n";
binmode GRAPHFILE; # Required for Microsoft OS
binmode STDOUT;
# copy graphics file to STDOUT
while ( $cb = read( GRAPHFILE, $data, 4096 ) ) {
print $data;
}
close GRAPHFILE;
unlink GRAPHFILE; # Delete graphics file
|
![]()
sine.gp set terminal png |
SVG 1.1 became a W3C Recommendation in January 2003.
Sun Microsystems, Adobe, Apple, IBM, and Kodak are some of the well-known organizations that have been involved in defining SVG.
Advantages of using SVG over other image formats (like JPEG and GIF):
SVG has some predefined shape elements:
The following chapters will explain each element, starting with the rect element.
The <rect> tag is used to create a rectangle and variations of a rectangle shape.
As an example, copy and save the file as "rect1.svg".
|
<?xml version="1.0" ?> <svg width="30" height="30"> <rect width="30" height="10" style="fill:rgb(0,0,255); stroke-width:1; stroke:rgb(0,0,0)"/> </svg> |
Code explanation:
Copy and save the file as "rect1.htm", which loads and displays "rect1.svg".
![]()
<html> <body> <embed src="rect1.svg" width="40"
height="40" type="image/svg-xml" /> </body> </html> |
Another example
|
<?xml version="1.0"?> <svg width="30" height="30"> <rect x="20" y="20" width="25" height="25" style="fill:blue;stroke:pink;stroke-width:5; fill-opacity:0.1;stroke-opacity:0.9"/> </svg> |
Code explanation:
Another example, create a rectangle with rounded corners:
<?xml version="1.0"?> <svg width="300" height="300" > <rect x="20" y="20" rx="20" ry="20" width="250" height="100" style="fill:red;stroke:black; stroke-width:5;opacity:0.5"/> </svg> |
Code explanation:
|
<?xml version="1.0" ?> <svg width="60" height="60"> <circle cx="20" cy="20" r="15" stroke="black" stroke-width="2" fill="red"/> </svg> |
![]()
Further Information - None presently for xy, check documentation
on gd for making changes to font sizes, etc.