#!/usr/bin/perl -w # mathinhtml is copyright (C) 2003 Michael J Miller # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License. This program # is distributed without any warranty (not even the implied warranty of # merchantability or fitness for a particular purpose). use strict; use File::Basename; my $programname="mathinhtml v0.62 (4-Mar-2003)"; ####################################################################### # This is where you tell mathinhtml the names of your programs. # If you don't have one installed, give it the name "". my $TEX="tex"; # "tex" for everyone my $DVIPS="dvips"; # "dvips" for everyone my $GNUPLOT="gnuplot"; # "gnuplot" for Linux; "pgnuplot" for Windows my $GHOSTSCRIPT="gs"; # "gs" for Linux; "gswin32c" for Windows my $OVERSAMPLE=1; # Set to 1 for best screen quality. # Set to 2 or higher for better print quality. ####################################################################### # This section establishes the rules by which mathinhtml translates # the contents of an element into the requested image/text. my %rules; $rules{"TEX"}={ input1 => "\\nopagenumbers _CONTENTS_ \\bye", action1 => "$TEX -interaction=batchmode tempfile.1", action2 => "$DVIPS -E -q tempfile.dvi -o tempfile.ps", scale => 1.5, attrib => 'ALIGN="CENTER"' }; $rules{"EQ"}={%{$rules{"TEX"}}}; $rules{"EQ"}{"input1"} ="\\nopagenumbers \$\$ _CONTENTS_ \$\$ \\bye"; my $ps_setup="set terminal postscript eps enhanced color 24;". "set output 'tempfile.ps';"; $rules{"GNUPLOT"}={ input1 => "$ps_setup _CONTENTS_ ", action1 => "$GNUPLOT tempfile.1", scale => 1, attrib => 'ALIGN="TOP"' }; $rules{"GR"}={%{$rules{"GNUPLOT"}}}; $rules{"GR"}{"input1"}="$ps_setup; set zeroaxis; set xtics axis;". "set ytics axis; set noborder; set nokey; _CONTENTS_ "; $rules{"EQN"}={ input1 => "_CONTENTS_ ", action1 => "tex2html tempfile.1" }; my @tempfiles=qw/ tempfile.1 tempfile.dvi tempfile.log tempfile.ps /; ############################################################### # This section defines subroutines for manipulating png files my %crctable; # Remember table for crc checksums sub checksum { # Computes the CRC checksum used in png files my $crc=0xFFFFFFFF; foreach (split //, $_[0]){ my $n=( $crc ^ (unpack 'C', $_) ) & 0xFF; if (!$crctable{$n}){ my $c=$n; foreach (1..8) { $c= ($c & 1) ? 0xEDB88320^($c>>1) : ($c>>1) }; $crctable{$n}=$c; }; $crc=$crctable{$n} ^ ($crc>>8); }; return $crc ^ 0xFFFFFFFF; } sub createchunk { # Creates a valid png chunk from $string my $string=$_[0]; my $len=pack 'N', (length $string)-4; # Chunk type takes up 4 bytes my $crc=pack 'N', checksum $string; return $len.$string.$crc; } sub findchunk { # Finds the first chunk beginning with $type in $string my ($type, $string)=@_; my $t=length $type; my $len; for (my $k=8; $k; } sub ps2png { # Converts postscript to png my ($psfilename, $pngfilename, $resolution)=@_; (slurp $psfilename) =~ m/^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)/m; my $translate="-$1 -$2 translate"; my $width=int($resolution*($3-$1)/72); my $height=int($resolution*($4-$2)/72); system "$GHOSTSCRIPT -dNOPAUSE -dBATCH -dQUIET -sDEVICE=png256 ". "-dPARANOIDSAFER -dTextAlphaBits=4 -dGraphicsAlphaBits=4 ". "-g${width}x$height -r$resolution -sOutputFile=$pngfilename ". "-c $translate -f $psfilename"; #Compression? return ($width, $height); } sub modifypng { # Writes transparency & mathinhtml$key chunks to $pngfilename my ($pngfilename, $key)=@_; my $png=slurp $pngfilename; substr($png, -12, 0)=createchunk "tEXtmathinhtml\0$key"; my ($k, $len, $palette)=findchunk("PLTE", $png); my $trans="tRNS"; $trans=$trans.($1 eq "\xFF\xFF\xFF" ? "\x00" : "\xFF") while ($palette =~ m/(...)/g); substr($png, $k+$len+12, 0)=createchunk $trans; open FILE, "> $pngfilename"; binmode FILE; print FILE $png; close FILE; } my %index; sub createindex{ # Creates an index of pre-existing image files foreach my $filename (grep /\.png$/, @_) { my $imgstuff=slurp $filename; my ($dummy1, $dummy2, $key)=findchunk("tEXtmathinhtml\0",$imgstuff); if ($key) { my $w=unpack 'N', substr $imgstuff, 16, 4; my $h=unpack 'N', substr $imgstuff, 20, 4; # print "Indexing $filename\t${width}x$height\t$key\n"; $index{"$key"}={ filename=>$filename, width=>$w, height=>$h }; }; }; } my $tagnames=join '|', keys %rules; # A list of defined tags sub translate { # Translates an element into its correcponding image/text my $key=$_[0]; my ($dummy, $tagname, $contents)=split " ", $key, 3; # $dummy is $OVERSAMPLE for (my $i=1; defined $rules{$tagname}{"input$i"}; $i++){ my $input=$rules{$tagname}{"input$i"}; $input =~ s/_CONTENTS_/$contents/g; open FILE, "> tempfile.$i"; print FILE "$input\n"; close FILE; } print STDERR "Translating $key\n"; my $output; for (my $i=1; defined $rules{$tagname}{"action$i"}; $i++){ $output=qx/ $rules{$tagname}{"action$i"} /; } if (-s "tempfile.ps"){ my $resolution=72*$OVERSAMPLE*$rules{$tagname}{"scale"}; my ($width, $height)=ps2png("tempfile.ps", "tempfile.png", $resolution); modifypng("tempfile.png",$key); my $num=0; while (-s "IMG_$num.png") { $num++ }; my $imgname="IMG_$num.png"; rename "tempfile.png", $imgname; $index{$key}= {filename=>$imgname, width=>$width, height=>$height }; } else { $output =~ s/\s+/ /g; $index{$key}=$output }; unlink @tempfiles; } sub replace { # Replaces a element by its translation my $qstr=q/(?:"[^"]*?"|'[^']*?')/; # Matches a quoted string my ($tagname, $attributes, $contents)= $_[0] =~ m|^<($tagnames)((?:\s+\w+=$qstr)*)\s*>(.*?)$|is; $contents =~ s/\s+/ /g; $contents =~ s/^ //; $contents =~ s/ $//; my $key="$OVERSAMPLE $tagname $contents"; if (! exists $index{$key}){ &translate($key) }; if (ref $index{$key}){ for ($contents) { # replace "forbidden" html characters s/&/&/g; s//>/g; s/"/"/g; s/'/'/g; # replace backslash with space (may make TeX contents more readable) s/\\/ /g; }; $attributes=" SRC=\"$index{$key}{'filename'}\"". " WIDTH=\"".($index{$key}{'width'}/$OVERSAMPLE)."\"". " HEIGHT=\"".($index{$key}{'height'}/$OVERSAMPLE)."\"". " ALT=\"$contents\" TITLE=\"$contents\"". " $rules{$tagname}{'attrib'} $attributes"; while ($attributes =~ s/\s(\w+)=$qstr(.*?)\s\1=($qstr)/ $1=$3 $2 /is){}; for ($attributes){ s/\s+/ /g; s/ $// }; return ""; } else { return $index{$key} }; } ################################################################# # This is the main executable. print STDERR "\n$programname\nCopyright (C) 2003 Michael J Miller\n". "This program comes with absolutely no warranty.\n\n"; chdir dirname $ARGV[0]; opendir DIR, dirname $ARGV[0]; my @files=readdir DIR; closedir DIR; die "Please delete temporary file(s): @_\n" if (@_=grep/^tempfile\./, @files); createindex @files; my $filename=basename $ARGV[0]; $_=slurp $filename; s||\n\n|i; my @sections= m/(.*?)(

|
|

  • ||.$)/igs; $filename =~ s/\.mih$//; open(HTMLFILE, "> $filename.html"); foreach (@sections){ s|<($tagnames)[\s>].*?|&replace($&)|iesg; print HTMLFILE "$_"; } close HTMLFILE;