We are using plexus as http server so everything in it is written perl iincluding ISMAP handling. I hacked the file for that so that it handles rectangular areas, areas specified by a mask and by a mask inside a rectangle. The mask is constructed from a X11 bitmap by another perl program, it pays to have a binary format for the mask as parsing of bitmaps is expensive. Here are the relevant pices of code: Example of format for the map specification: default http://www.su.se/ rect-bitmask 397 222 62 86 inst.mask sverige.html rect-bitmask 616 362 41 43 metro.mask tunnelb.html rect-bitmask 115 442 40 33 SL.mask tider/TillSthlm.html rect-bitmask 397 528 40 33 SL.mask tider/FranSthlm.html rect-bitmask 445 178 86 45 hus5.mask elevsal/elevsalar.html rect 0 0 683 558 http://www.su.se/ Internal plexus file for handling of requests, lots of perl4-isms: # decode.pl -- image selection decoder # # decode.pl,v 2.8 1993/08/31 18:18:14 sanders Exp # # Chris McRae <mcrae@ckm.ucsf.edu>, May 1993 # bitmasks added by Tony Sanders <sanders@bsdi.com>, June 1993 # rect-bitmasks added by teke # # This is the support code for decoding images. # # FYI about bitmasks: # For large images using masks you'll want to scale the mask by some factor # depending on how accurate the results must be. It would be better to # have a ppm style mask with each "color" being a different object. If # you write this let me know. Currently you need a mask for each object. # The code doesn't currently support this. # map_handle pixmask pixmap_file color1 URL1 [menu desc] # map_handle pixmask pixmap_file color2 URL2 [menu desc] # # &do_decode -- decides what to do (rectangle decoding is built-in) # ®ion -- front end to &loadmask and &pixel that caches bitmasks # &loadmask -- reads the image file into memory # &pixel -- test if a pixel is set, image must already be loaded by &loadmask # &rnd -- internal routine for &loadmask for rounding up to nearest byte # # XXX: executable URLs # XXX: scaled bitmasks # # Example config lines: # $map{'decode'} = '&do_decode($path, $query)'; sub do_decode { local($map_handle, $query) = @_; local($_, @lines, @menu) = (defined($query) && $query); local($X, $Y) = split(',', $_); # unpack $query: x,y local($map_config_file) = $plexus{'decode_config'}; local($title) = "Object menu for image: $map_handle"; MAP_OPEN: { # extract lines from MAP for this object ($map_handle) @lines = (); &open(MAP, $map_config_file) || die "$map_config_file: $!"; while (<MAP>) { (/^\s*$/ || /^\s*#/) && next; $map_handle ? s/^\s*$map_handle\s+// && push(@lines, $_) : push(@lines, $_); if (s/^\s*config-directory\s+//) { s/\s+$//; $map_config_file = "$_/$map_handle"; $map_handle = undef; close MAP; redo MAP_OPEN; } } close(MAP); # map_handle default URL # map_handle title default_title_for_automenu # config-directory map_config_directory # map_handle config-file map_config_file # map_handle rect-bitmask bitmask_file x y width height URL [menu desc] # map_handle bitmask bitmask_file width height URL [menu desc] # map_handle rect x y width height URL [menu desc] foreach (@lines) { split; # into @_ if ($_[0] =~ /default/i) { return &url_location($_[1]) unless defined($query); } elsif ($_[0] =~ /title/i) { shift @_; shift @_; $title = join(" ", @_); } elsif ($_[0] =~ /config-file/i) { # redirect to another file &error('internal_error', "too many lines for $map_handle in $map_config_file") unless $#lines == 0; # only one allowed $map_config_file = $_[1]; redo MAP_OPEN; } elsif ($_[0] =~ /rect-bitmask/i) { # decode by rectangle and bitmask local($x, $y, $w, $h, $bitmask,$URL) = @_[1..6]; unless (defined($query)) { splice(@_,0,7,()); # delete 0..7 push(@menu, join(" ", ($URL, @_))); # rest is menu text next; } if (($x < $X) && (($x+$w) > $X) && ($y < $Y) && (($y+$h) > $Y)) { ®ion($bitmask, $w, $h, $X - $x, $Y - $y) && return &url_location($URL); } } elsif ($_[0] =~ /bitmask/i) { # decode by bitmask local($bitmask, $w, $h, $URL) = @_[1..4]; unless (defined($query)) { splice(@_,0,5,()); # delete 0..5 push(@menu, join(" ", ($URL, @_))); # rest is menu text next; } # XXX: Need to embed width and height in the mask file ®ion($bitmask, $w, $h, $X, $Y) && return &url_location($URL); } elsif ($_[0] =~ /rect/i) { # decode by rectangle local($x, $y, $w, $h, $URL) = @_[1..5]; unless (defined($query)) { splice(@_,0,6,()); # delete 0..6 push(@menu, join(" ", ($URL, @_))); # rest is menu text next; } if (($x < $X) && (($x+$w) > $X) && ($y < $Y) && (($y+$h) > $Y)) { return &url_location($URL); } } } } # No $query or nothing found -- this menu will only contain # the elements in the last config file read. &MIME_header('ok', 'text/html'); print "<HEAD>\n<TITLE>$title</TITLE>\n</HEAD>\n"; print "<BODY>\nYou can select one of:\n<UL>\n"; foreach (@menu) { split(" ", $_, 2); print "<LI> <A HREF=\"$_[0]\">$_[1]</A>\n"; } print "</UL>\n</BODY>\n"; } sub rnd { local($value, $incr) = @_; ($value + ($incr-1)) & ~($incr-1); } sub loadmask { local(*image) = @_; local($bits); # because perl can't sysread into $image{'bits'} $image{'scanlen'} = &rnd($image{'width'}, 8); # whole bytes open(BITS, $image{'filename'}) || die "$image{'filename'}: $!"; sysread(BITS, $bits, $image{'scanlen'} * $image{'height'} / 8); close(BITS); $image{'bits'} = $bits; } sub pixel { local(*image, $x, $y) = @_; local($offset) = int((($y * $image{'scanlen'}) + $x)/8); local($byte) = unpack("c", substr($image{'bits'}, $offset, 4)) & 0xff; return (($byte & (1<<($x%8))) != 0); } $imgatom = "img000"; # generate unique names %imgatom = (); sub region { local($file, $width, $height, $x, $y) = @_; local($a); # cached? defined($a = $imgatom{$file}) || do { $a = $imgatom{$file} = $imgatom++; # string increment eval " \$$a{'filename'} = \$file; \$$a{'width'} = \$width; \$$a{'height'} = \$height; &main'loadmask(*$a);"; die $@ if $@; }; return eval "&main'pixel(*$a, \$x, \$y)"; } 1; ---------------------------------------------------------------------- Program converting an X11 bitmask to binary format used by pixel: #!/usr/local/bin/perl $/ = undef; $bm = <>; ($width,$height,$bitimage) = $bm =~ /\#define.*_width\s+([0-9]+)\s+\#define.*_height\s+([0-9]+)\s+static.*char.*bits\[\]\s+=\s+\{((.|\n)*)\};/; $bitimage =~ s/,\s*0x//og; $bitimage =~ s/^\s*0x//; $bitimage =~ s/,?\s*$//; print pack("h*",$bitimage);