#!/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.61 (28-Feb-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. # BUG: Images are not recreated when $OVERSAMPLE is changed. ####################################################################### # 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 a 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 verifychunk { # Verifies that a purported png chunk is valid $_[0] =~ m/^(....)(.*)(....)$/; my $len=unpack 'N', $1; my $string=$2; my $crc=unpack 'N', $3; if ($len+4 != length $string) { return 0 } elsif ($crc != checksum $string) { return 0 } else { return 1 }; } ############################################################### # This section defines the subroutines "translate" (which translates # an element to its corresponding image/text) and "replace" (which # replaces an element by its translation). my %archive; # This hash catalogs those image files that have already been # created, so that existing images will not be recreated. my $tagnames=join '|', keys %rules; sub slurp { local $/=undef; open FILE, "< $_[0]"; binmode FILE; return ; } sub translate { my $key=$_[0]; my ($tagname, $contents)=split " ", $key, 2; 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 $num=0; while (-s "IMG_$num.png") { $num++ }; my $imgname="IMG_$num.png"; my $psfile=slurp "tempfile.ps"; $psfile =~ m/^%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)/m; my $translate="-$1 -$2 translate"; my $resolution=72*$OVERSAMPLE*$rules{$tagname}{"scale"}; my $width=int($resolution*($3-$1)/72); my $height=int($resolution*($4-$2)/72); system "$GHOSTSCRIPT -dNOPAUSE -dBATCH -dQUIET -sDEVICE=png16m ". "-dPARANOIDSAFER -dTextAlphaBits=4 -dGraphicsAlphaBits=4 ". "-g${width}x$height -r$resolution -sOutputFile=$imgname ". "-c $translate -f tempfile.ps"; my $png=slurp $imgname; substr($png, -12, 0)=createchunk "tEXtmathinhtml\0$tagname $contents"; my $trans; if (substr($png, 25, 1) eq "\x00") { $trans="\0\xFF" } elsif (substr($png, 25, 1) eq "\x02") { $trans="\0\xFF\0\xFF\0\xFF" } elsif (substr($png, 25, 1) eq "\x03") { $trans="\0" } else { print STDERR "Bad image data?\n" }; substr($png, index($png,"IDAT")-4, 0)=createchunk "tRNS$trans"; open FILE, "> $imgname"; binmode FILE; print FILE $png; close FILE; # This is the best way to do transparency, but the result is not # rendered correctly by the Windows version of Internet Explorer. # system "convert -size $geometry xc:transparent -matte blank.png"; # system "composite $imgname blank.png $imgname $imgname"; # unlink "blank.png"; $archive{$key}= {filename=>$imgname, width=>$width, height=>$height }; } else { $output =~ s/\s+/ /g; $archive{$key}=$output }; unlink @tempfiles; } sub replace { 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="$tagname\t$contents"; if (! exists $archive{$key}){ &translate($key) }; if (ref $archive{$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=\"$archive{$key}{'filename'}\"". " WIDTH=\"".($archive{$key}{'width'}/$OVERSAMPLE)."\"". " HEIGHT=\"".($archive{$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 $archive{$key} }; } ############################################################## # This section defines the subroutine createarchive sub createarchive{ opendir DIR, dirname $ARGV[0]; my @pngfiles=grep /\.png$/, readdir DIR; closedir DIR; foreach my $filename (@pngfiles) { my $imgstuff=slurp $filename; my $k=index $imgstuff, "tEXtmathinhtml\0"; # 15 characters if ($k>-1){ my $len=unpack 'N', substr $imgstuff, $k-4, 4; my $comment=substr $imgstuff, $k+15, $len-11; my ($tagname, $contents)=split " ", $comment, 2; my $width=unpack 'N', substr $imgstuff, 16, 4; my $height=unpack 'N', substr $imgstuff, 20, 4; # print "Archiving $filename\t${width}x$height\t$tagname\t$contents\n"; $archive{"$tagname\t$contents"}= { filename => $filename, width => $width, height => $height }; }; }; } ################################################################# # 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]; createarchive; 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;