[system] / trunk / webwork-modperl / lib / WeBWorK / PG / ImageGenerator.pm Repository:
ViewVC logotype

View of /trunk/webwork-modperl/lib/WeBWorK/PG/ImageGenerator.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1517 - (download) (as text) (annotate)
Tue Sep 23 21:12:36 2003 UTC (9 years, 7 months ago) by sh002i
File size: 7316 byte(s)
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