Subject: Use gs to render gif images on the fly
From: [email-masked] (Gisle Aas)
Date: 25 Oct 1993 15:30:38 GMT
Newsgroups: comp.infosystems.www

Below is a package for the Plexus http server that shows you how you
can make Ghostscript render some graphics for you on the fly.  This
might be useful for those of you who want to include Greek letters and
other symbols in their html documents. Before you install it you might
want to try some of the following URLs:

   http://nora.nr.no/fancy/clock.gif
   http://nora.nr.no/fancy/clock.gif?400
   http://nora.nr.no/fancy/glyph/g
   http://nora.nr.no/fancy/glyph/yen?Times-Roman,300
   http://nora.nr.no/fancy/glyph/beta?Symbol
   http://nora.nr.no/fancy/glyph/beta?Symbol,300
   http://nora.nr.no/fancy/glyph/beta?Symbol,300,60

Please return enhancements that you make to this code back to me. Enjoy!

---------------------------------------------------------------------------
#!/local/bin/perl

# $Id: fancy.pl,v 1.1 1993/10/25 14:37:51 aas Exp $

# URI: /fancy/clock.gif[?<size>]
# URI: /fancy/glyph/<char>[?<font>][,<size>][,<background>]

# This package shows how one might use ghostscript to render GIF
# images on the fly.  The package is currently able to return an
# analog clock showing the local time and to return an one character
# glyph from any postscript font.
#
# Author: Gisle Aas, Norsk Regnesentral, Oslo

package fancy;

$afmdir = "/usr/openwin/lib/fonts/afm";
$space  = 3; # space around the graphics

sub do
{
    local($rest, $query) = @_;

    if ($rest eq "clock.gif") {
        if ($query =~ /^\d+/) { $dim = int($query) } else { $dim = 100; }
	&clock($dim);
    } elsif ($rest =~ s,^glyph/,,) {
        &glyph($rest,$query);
    } else {
	&main'error('bad_request', "Don't know about $rest");
    }
}

sub glyph
{
    local($char, $param) = @_;
    local($font,$size,$bg) = split(",", $param);
    $font = "Times-Roman" unless length $font;
    $size = 100 if $size <= 0;
    if (defined $bg) { $bg /= 100 } else { $bg = 1 }
    $bg = 1 if $bg < 0 || $bg > 1;
  
    open(AFM, "$afmdir/$font.afm") ||
        &main'error('internal_error', "No font metrics file for font $font");
    while (<AFM>) {
       next unless /^C\s/;
       last if /\bN\s+$char\b/o;
    }
    close(AFM);
    unless (length $_) {
       &main'error('internal_error', "No char called $char in font $font");
    }
    ($code) = /^C\s+(-?\d+)/;
    ($llx,$lly,$urx,$ury) = /\bB\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)/;
    if ($code <= 0) {
       &main'error('internal_error', "Char $char is not encoded");
    }
    $char = sprintf("\\%03o", $code);
    grep ($_ *= $size/1000, $llx,$lly,$urx,$ury);
    $wx = int(($urx - $llx) + 2*$space);
    $wy = int(($ury - $lly) + 2*$space);

    open(GS,"|/local/gnu/bin/gs -sDEVICE=gif8 -sOutputFile=- -q -g${wx}x${wy} -") ||
         &main'error('internal_error', "Can't run ghostscript");
    &main'MIME_header('ok', 'image/gif');
    print GS <<"EOF" if $bg != 1;
%!
gsave $bg setgray clippath fill grestore
EOF
    print GS <<"EOF";
%!
$llx neg $lly neg translate
$space $space moveto
/$font findfont $size scalefont setfont
($char)show
showpage
EOF
    close GS;    
}

sub clock
{
    local($dim) = shift;
    open(GS,"|/local/gnu/bin/gs -sDEVICE=gif8 -sOutputFile=- -q -g${dim}x${dim} -") ||
         &main'error('internal_error', "Can't run ghostscript");
    &main'MIME_header('ok', 'image/gif');
    select GS;
    if ($dim != 100) {
       local($scale) = $dim/100;
       print "%!\n\n $scale dup scale\n";
    }
    &pstime;
    close(GS);
}

# This procedure reads the local time and outputs a postscript program which
# shows an analog clock.  The dimentions on the picture is 100 x 100 points.

sub pstime
{
    ($sec,$min,$hour) = localtime;
    $clock = sprintf("%d:%02d", $hour, $min);
    $minG  = $min*6;
    $hourG = ($min/60 + $hour)*30;
    print <<"EOF";
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 100 100

50 50 translate
0.5 dup scale

0.85 setgray clippath fill

0.7 setgray
0 0 97 0 360 arc stroke
3 setlinewidth

%/Times-Roman findfont 8 scalefont setfont
gsave
60 rotate
1 1 12 {%for
  pop % 90 4 moveto (  ) cvs show
  90 0 moveto 100 0 lineto stroke
  -30 rotate
} for
grestore

%0 setgray
%/Times-Roman findfont 20 scalefont setfont
%0 -30 moveto ($clock)dup stringwidth pop 2 div neg 0 rmoveto show

9 setlinewidth
0.6 setgray 
0 0 moveto
$hourG sin 60 mul
$hourG cos 60 mul
lineto stroke
0 0 9 0 360 arc fill

6 setlinewidth
0.4 setgray
0 0 moveto
$minG sin 90 mul
$minG cos 90 mul
lineto stroke
0 0 6 0 360 arc fill

showpage
EOF
}

1;
--
¤ Gisle Aas - Norsk Regnesentral                     <[email-masked]>