Parent Directory
|
Revision Log
equationcache module was moved.
1 ################################################################################ 2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project 3 # $Id$ 4 ################################################################################ 5 6 package WeBWorK::PG::ImageGenerator; 7 8 =head1 NAME 9 10 WeBWorK::PG::ImageGenerator - create an object for holding bits of math for 11 LaTeX, and then to process them all at once. 12 13 =head1 SYNPOSIS 14 15 FIXME: add this 16 17 =cut 18 19 use strict; 20 use warnings; 21 use WeBWorK::EquationCache; 22 use WeBWorK::Utils qw(readDirectory makeTempDirectory removeTempDirectory); 23 24 use constant PREAMBLE => <<'EOF'; 25 \documentclass[12pt]{article} 26 \nonstopmode 27 \usepackage{amsmath,amsfonts,amssymb} 28 \def\gt{>} 29 \def\lt{<} 30 \usepackage[active,textmath,displaymath]{preview} 31 \begin{document} 32 EOF 33 use constant POSTAMBLE => <<'EOF'; 34 \end{document} 35 EOF 36 use constant DVIPNG_ARGS => join " ", qw( 37 -x4000.5 38 -bgTransparent 39 -Q6 40 -mode toshiba 41 -D180 42 ); 43 44 =head1 METHODS 45 46 =over 47 48 =item new 49 50 Returns a new ImageGenerator object. C<%options> must contain the following 51 entries: 52 53 tempDir => directory in which to create temporary processing directory 54 dir => directory for resulting files 55 url => url to directory for resulting files 56 basename => base name for image files 57 latex => path to latex binary 58 dvipng => path to dvipng binary 59 60 C<%options> may also contain the following entries: 61 62 useCache => boolean, whether to use global image cache 63 cacheDir => directory for resulting files 64 cacheURL => url to imageCacheDir 65 cacheDB => path to cache database file 66 67 If C<useCache> is true, then C<basename> is ignored, and C<cacheDir> 68 and C<cacheURL> override C<dir> and C<url>, respectively. 69 70 =cut 71 72 sub new { 73 my ($invocant, %options) = @_; 74 my $class = ref $invocant || $invocant; 75 my $self = { 76 names => [], 77 strings => [], 78 %options, 79 }; 80 81 if ($self->{useCache}) { 82 $self->{dir} = $self->{cacheDir}; 83 $self->{url} = $self->{cacheURL}; 84 $self->{basename} = ""; 85 $self->{equationCache} = WeBWorK::EquationCache->new(cacheDB => $self->{cacheDB}); 86 } 87 88 bless $self, $class; 89 } 90 91 =item add($string, $mode) 92 93 Adds the equation in C<$string> to the object. C<$mode> can be "display" or 94 "inline". If not specified, "inline" is assumed. Returns the proper HTML tag 95 for displaying the image. 96 97 =cut 98 99 sub add { 100 my ($self, $string, $mode) = @_; 101 102 my $names = $self->{names}; 103 my $strings = $self->{strings}; 104 my $dir = $self->{dir}; 105 my $url = $self->{url}; 106 my $basename = $self->{basename}; 107 my $useCache = $self->{useCache}; 108 109 # if the string came in with delimiters, chop them off and set the mode 110 # based on whether they were \[ .. \] or \( ... \). this means that if 111 # the string has delimiters, the mode *argument* is ignored. 112 if ($string =~ s/^\\\[(.*)\\\]$/$1/s) { 113 $mode = "display"; 114 } elsif ($string =~ s/^\\\((.*)\\\)$/$1/s) { 115 $mode = "inline"; 116 } 117 # otherwise, leave the string and the mode alone. 118 119 # assume that a bare string with no mode specified is inline 120 $mode ||= "inline"; 121 122 # now that we know what mode we're dealing with, we can generate a "real" 123 # string to pass to latex 124 my $realString = ($mode eq "display") 125 ? '\(\displaystyle{' . $string . '}\)' 126 : '\(' . $string . '\)'; 127 128 # determine what the image's "number" is 129 my $imageNum = ($useCache) 130 ? $self->{equationCache}->lookup($realString) 131 : @$strings + 1; 132 133 # get the full file name of the image 134 my $imageName = ($basename) 135 ? "$basename.$imageNum.png" 136 : "$imageNum.png"; 137 138 # store the full file name of the image, and the "real" tex string to the object 139 push @$names, $imageName; 140 push @$strings, $realString; 141 #warn "ImageGenerator: added string $realString with name $imageName\n"; 142 143 # ... and the full URL. 144 my $imageURL = "$url/$imageName"; 145 146 my $imageTag = ($mode eq "display") 147 ? " <div align=\"center\"><img src=\"$imageURL\" align=\"middle\" alt=\"$string\"></div> " 148 : " <img src=\"$imageURL\" align=\"middle\" alt=\"$string\"> "; 149 150 return $imageTag; 151 } 152 153 =item render(%options) 154 155 Uses LaTeX and dvipng to render the equations stored in the object. If the key 156 "mtime" in C<%options> is given, its value will be interpreted as a unix date 157 and compared with the modification date on any existing copy of the first image 158 to be generated. It is recommended that the modification time of the source 159 file from which the equations originate be used for this value. If the key 160 "refresh" in C<%options> is true, images will be regenerated regardless of when 161 they were last modified. If neither option is supplied, "refresh" is assumed. 162 163 =cut 164 165 sub render { 166 my ($self, %options) = @_; 167 168 my $tempDir = $self->{tempDir}; 169 my $dir = $self->{dir}; 170 my $basename = $self->{basename}; 171 my $latex = $self->{latex}; 172 my $dvipng = $self->{dvipng}; 173 my $names = $self->{names}; 174 my $strings = $self->{strings}; 175 176 my $mtime = $options{mtime}; 177 my $refresh = $options{refresh} || ! defined $mtime; 178 # must refresh if no mtime is given 179 180 #unless ($refresh) { 181 # #my $firstImage = "$dir/$basename.1.png"; 182 # my $firstImage = "$dir/" . $names->[0]; 183 # if (-e $firstImage) { 184 # # return if first image newer than $mtime 185 # return if (stat $firstImage)[9] >= $mtime; 186 # } 187 #} 188 189 # determine which images need to be generated 190 my (@newStrings, @newNames); 191 for (my $i = 0; $i < @$strings; $i++) { 192 my $string = $strings->[$i]; 193 my $name = $names->[$i]; 194 if (-e "$dir/$name") { 195 #warn "ImageGenerator: found a file named $name, skipping string $string\n"; 196 } else { 197 #warn "ImageGenerator: didn't find a file named $name, including string $string\n"; 198 push @newStrings, $string; 199 push @newNames, $name; 200 } 201 } 202 203 return unless @newStrings; # Don't run latex if there are no images to generate 204 205 # create temporary directory in which to do TeX processing 206 my $wd = makeTempDirectory($tempDir, "ImageGenerator"); 207 208 # store equations in a tex file 209 my $texFile = "$wd/equation.tex"; 210 open my $tex, ">", $texFile 211 or die "failed to open file $texFile for writing: $!"; 212 print $tex PREAMBLE; 213 print $tex "$_\n" foreach @newStrings; 214 print $tex POSTAMBLE; 215 close $tex; 216 217 # call LaTeX 218 my $latexCommand = "cd $wd && $latex equation > latex.out 2> latex.err"; 219 my $latexStatus = system $latexCommand; 220 warn "$latexCommand returned non-zero status $latexStatus: $!" 221 if $latexStatus; 222 warn "$latexCommand failed to generate a DVI file" 223 unless -e "$wd/equation.dvi"; 224 225 # call dvipng 226 my $dvipngCommand = "cd $wd && $dvipng " . DVIPNG_ARGS . " equation > dvipng.out 2> dvipng.err"; 227 my $dvipngStatus = system $dvipngCommand; 228 #warn "$dvipngCommand returned non-zero status $dvipngStatus: $!" 229 # if $dvipngStatus; 230 231 # move/rename images 232 foreach my $image (readDirectory($wd)) { 233 # only work on equation#.png files 234 next unless $image =~ m/^equation(\d+)\.png$/; 235 236 # get image number from above match 237 my $imageNum = $1; 238 239 #warn "ImageGenerator: found generated image $imageNum with name $newNames[$imageNum-1]\n"; 240 241 # move/rename image 242 #my $mvCommand = "cd $wd && /bin/mv $wd/$image $dir/$basename.$imageNum.png"; 243 my $mvCommand = "cd $wd && /bin/mv $wd/$image $dir/" . $newNames[$imageNum-1]; 244 my $mvStatus = system $mvCommand; 245 warn "$mvCommand returned non-zero status $mvStatus: $!" 246 if $mvStatus; 247 } 248 249 # remove temporary directory (and its contents) 250 removeTempDirectory($wd); 251 } 252 253 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |