Extension UML Code 0.4.0 unix

From mediawiki.org

Modified MetaUML.php that should work at least in Ubuntu Linux. Major changes involve:

  • Changed backslash (\) to slash (/) in file path names.
  • Remove .exe extensions to program (in this case only affected mpost)
  • Changed non-existent '-quiet' mpost option for '-interactive=nonstopmode'

It kind of works with simple examples but it might require finer tuning.

<?php
/**
 * Parser hook extension adds a <uml> tag to wiki markup for rendering UML
 * diagrams within a wiki page using MetaUML.
 *
 * Parameters:
 *   density=width       passed to ImageMagick to set resolution of the image in DPI.  
 *   redraw              force diagram to be redrawn by deleting cached image. 
 *
 */
  
// Make sure we are being called properly
if( !defined( 'MEDIAWIKI' ) ) {
    echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
    die( -1 );
}
 
//Avoid unstubbing $wgParser too early on modern (1.12+) MW versions, as per r35980
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
        $wgHooks['ParserFirstCallInit'][] = 'wfMetaUMLExtension';
} else {
        $wgExtensionFunctions[] = 'wfMetaUMLExtension';
}
 
$wgExtensionCredits['parserhook'][] = array(
        'name' => 'UML',
        'version' => '0.4',
        'author' => 'Bryan A.',
        'url' => 'http://www.mediawiki.org/wiki/Extension:UML',
        'description' => 'Renders a UML model from text using MetaUML.'
);
 
$image_format = "png";
$tmp_filename = md5(rand());
$mpost_path   = "mpost";
$density      = "100%";
$redraw       = false;
 
function wfMetaUMLExtension() {
    global $wgParser;
    # register the extension with the WikiText parser
    # the first parameter is the name of the new tag.
    # In this case it defines the tag <uml> ... </uml>
    # the second parameter is the callback function for
    # processing the text between the tags
    $wgParser->setHook( 'uml', 'renderUML' ); 
    return true;
}
 
    /**
     * wraps a minimalistic MetaUML document around the formula and returns a string
     * containing the whole document as string.
     *
     * @param string model in MetaUML format
     * @returns minimalistic MetaUML document containing the given model
     */
    function wrap_formula($MetaUML_Source) {
      $string  = "input metauml;\n\n";
      $string .= "beginfig(1);\n";
      $string .= "$MetaUML_Source\n";
      $string .= "endfig;\n\n";
      $string .= "end\n";
 
      return $string;
    }
 
    /**
     * Renders a MetaUML model by the using the following method:
     *  - write the formula into a wrapped tex-file in a temporary directory
     *    and change to it
     *  - Create an incomplete Postscript file using MikTex (mpost)
     *  - Patch the Postscript with some missing procedures     
     *  - convert, trim and add transparency by using 'convert' from the
     *    imagemagick package.
     *  - Save the resulting image to the picture cache directory using an
     *    md5 hash as filename. Already rendered models can be found directly
     *    this way.
     *
     * @param string MetaUML model
     * @returns true if the picture has been successfully saved to the picture
     *          cache directory
     */
    function renderMetaUML($MetaUML_Source) {
      global $wgMathDirectory, $wgMathPath, $wgTmpDirectory, $wgDvipsCommand;
      global $wgImageMagickConvertCommand, $wgImageMagickIdentifyCommand, $image_format, $tmp_filename, $mpost_path, $density; 

      $MetaUML_document = wrap_formula($MetaUML_Source);
 
      $current_dir = getcwd();
 
      chdir($wgTmpDirectory);
 
      // create temporary latex file
      $winPath = $wgTmpDirectory."/".$tmp_filename.".mp";
      $fp = fopen($winPath,"a+");
      $w = fputs($fp,$MetaUML_document);
      fclose($fp);
 
      // create temporary Postscript file
      #$command = $mpost_path." -quiet ".$winPath;
      $command = $mpost_path." -interaction=nonstopmode ".$winPath;
 
      $status_code = exec($command); 

 
      if(!file_exists($wgTmpDirectory."/".$tmp_filename.".1")) {
          cleanTemporaryDirectory(); 
          chdir($current_dir); 
          return false; 
      }
 
      // Fix mpost output by adding Postscript procedures
      $infile  = @fopen($wgTmpDirectory."/".$tmp_filename.".1", "r");
      $outfile = @fopen($wgTmpDirectory."/".$tmp_filename.".ps", "a+");
 
      if ($infile) {
        // Copy the first line (%!PS)
        $buffer = fgets($infile);  // , 4096);
        fputs($outfile, $buffer);
 
        // Add the missing procedures
        fputs($outfile, "/ptmr8r {/ptmr8r findfont} def\n");
        fputs($outfile, "/fshow {scalefont setfont show} def\n");
 
        // Copy the rest of the file
        while (!feof($infile)) {
            $buffer = fgets($infile);  // , 4096);
             fputs($outfile, $buffer);
        }
        fclose($infile);
        fclose($outfile);
      }
 
 
      // ImageMagick convert ps to image and trim picture
      $command = $wgImageMagickConvertCommand." -density ".$density.
                  " -trim -transparent \"#FFFFFF\" ".$tmp_filename.".ps ".
                  $tmp_filename.".".$image_format;
      $status_code = exec($command);
 
      // copy temporary formula file to cahed formula directory
      $latex_hash = md5($MetaUML_Source);
      $filename = $wgMathDirectory."/uml-".$latex_hash.".".$image_format;
 
      $status_code = copy($tmp_filename.".".$image_format,$filename);
 
      cleanTemporaryDirectory();
 
      if (!$status_code) { 
        chdir($current_dir); 
        return false; 
      }
      chdir($current_dir);
 
      return true;
    }
 
    /**
     * Cleans the temporary directory
     */
    function cleanTemporaryDirectory() {
      global $wgTmpDirectory, $image_format, $tmp_filename;
 
      #unlink($wgTmpDirectory."/".$tmp_filename.".mp");
      unlink($wgTmpDirectory."/".$tmp_filename.".log");
      unlink($wgTmpDirectory."/".$tmp_filename.".1");
      unlink($wgTmpDirectory."/".$tmp_filename.".ps");
      unlink($wgTmpDirectory."/".$tmp_filename.".".$image_format);
    } 
 
    /**
     * Tries to match the MetaUML given as argument against the cache. 
     * If the picture has not been rendered before, it'll
     * try to render the MetaUML and drop it in the picture cache directory.
     *
     * @param string model in MetaUML format
     * @returns the webserver based URL to a picture which contains the
     * requested MetaUML model. If anything fails, the resultvalue is false.
     */
    function getImageURL($MetaUML_Source) {
      global $wgMathDirectory, $wgMathPath, $image_format, $redraw;
 
      $formula_hash = md5($MetaUML_Source);
 
      $filename = 'uml-' . $formula_hash.".".$image_format;
      $full_path_filename = $wgMathDirectory."/".$filename;
 
      if (is_file($full_path_filename) && ($redraw == true)) {
        unlink($full_path_filename);
      }
 
      if (is_file($full_path_filename)) {
        return $wgMathPath."/".$filename;
      } else {
        if (renderMetaUML($MetaUML_Source)) {
          return $wgMathPath."/".$filename;
        } else {
          return false;
        }
      }
    }

# The callback function for converting the input text to HTML output
function renderUML( $input, $argv ) {
  global $density, $redraw, $image_format;
 
  if (array_key_exists('density', $argv)) {
    $density = $argv['density'];
  }
 
  if (array_key_exists('redraw', $argv)) {
    $redraw = true;
  }
 
  if (array_key_exists('format', $argv)) {
    $image_format = $argv['format'];
  }
 
  $url = getImageURL($input);
 
  if ($url == false) {
    $text = "[An error occurred in MetaUML extension]";
  } else {
    $text = "<img src='$url'>";
  }
 
  return $text;
}