Extension:UML

From MediaWiki.org
Jump to: navigation, search
MediaWiki extensions manual - list
Crystal Clear action run.png
UML

Release status: beta

Implementation Tag
Description Renders a UML model from text using MetaUML
Author(s) Bryan_a
Last version 0.4.0 (2009-11-04)
License No license specified
Download see below
Example Syncleus Technology Wiki
Parameters

density=width, redraw

Check usage and version matrix

Contents


UML is an extension written for MediaWiki that renders a UML model from text using MetaUML. This extension is especially usefull to render very good looking diagrams, but you have to make the element placement by yourself. It is not well fitted for UML sketches (quick drawing with autoplacement).

      • UML, the language, is an open standard and there are other packages that use the extension ".uml," specifically starUML.

License [edit]

There isn't really any license associated to it.

Feel free to use it as you wish. This code can be shared without any restrictions. Be aware that, in GPL-like terms, this program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Usage [edit]

Just put a MetaUML model description between the <uml></uml> tag.

Attributes [edit]

density=width
passed to ImageMagick to set resolution of the image in DPI.
format=format
"png" (good quality, transparent background) "jpg" (white background - better for pasting into Word) etc
redraw
force diagram to be redrawn by deleting cached image.

Examples [edit]

Example 1:

<uml density="200">
Class.A("Point")
       ("+x: int",
        "+y: int") ();

Class.B("Circle")
       ("radius: int")
       ("+getRadius(): int",
        "+setRadius(r: int):void");

topToBottom(45)(A, B);

drawObjects(A, B);

clink(aggregationUni)(A, B)
</uml>

Example 2:

<uml redraw>
Begin.b;
Activity.eat("Eat something good", "from the kitchen");
Branch.enough;
Fork.fork("h", 50);
Activity.read("Read a book");
Activity.listen("Listen to music", "(and ignore it)");
Fork.join("h", 50);
End.e;

leftToRight.top(10)(read, listen);
Group.readListen(read, listen);

leftToRight(30)(b, eat);
topToBottom(20)(eat, enough, fork, readListen, join, e);

drawObjects(b, eat, enough, fork, readListen, join, e);

clink(transition)(b, eat);
clink(transition)(eat, enough);
link(transition)(pathStepX(enough.e, eat.e, 80));
clink(transition)(enough, fork);
clink(transition)(fork, read);
clink(transition)(fork, listen);
clink(transition)(read, join);
clink(transition)(listen, join);
clink(transition)(join, e);

item(iGuard)("still hungry")(obj.sw = enough.e + (20, 0));
item(iGuard)("had enough")(obj.nw = enough.s + (0, -4));
</uml>

Example 3:

<uml>
Begin.b;
  State.reading("Reading commands")();
  State.processing("Processing commands")();
End.e;

State.composite("Working")(b, reading, processing, e);
composite.info.left := composite.info.right := 10;
composite.info.drawNameLine := 1;

topToBottom(20)(b, reading, processing, e);
drawObject(composite);

clink(transition)(b, reading);
clink(transition)(reading, processing);
clink(transition)(processing, e);

ExitPoint.exit;
exit.c=(composite.right, reading.midy);
drawObject(exit);
item(iAssoc)("error")(obj.nw = exit.s);

clink(transition)(reading, exit);

State.error("Preparing error report")();
State.result("Writing result")();
End.theEnd;

topToBottom(20)(error, result, theEnd);
leftToRight(30)(exit, error);

drawObjects(error, result, theEnd);

clink(transition)(exit, error);
clink(transition)(error, result);
clink(transition)(result, theEnd);

link(transition)(rpathHorizontal(result.w, composite.right));
</uml>

Installation [edit]

Windows [edit]

  1. Copy & paste the code below in a file called MetaUML.php and place it in your extensions directory of your MediaWiki folder.
  2. Install MetaUML, ImageMagick and Ghostscript.
    1. Rename ImageMagic's convert.exe to imageconvert.exe to avoid confusion with Windows' convert
    2. Rename Ghostscript's gswin32c.exe to gs.exe
    3. Add "/ptmr8r /NimbusRomNo9L-Regu ;" (spaces and all) to Fontmap.GS in Ghostscript lib directory
  3. Put this line near the end of your LocalSettings.php in the MediaWiki root-folder to include the extension.
require_once('extensions/MetaUML.php');

Linux [edit]

--Zioalex 16:50, 4 November 2009 (UTC)

  1. Install imagemagick, ghostscript, texlive , texlive-metapost and texlive-fonts-recommended
  2. Copy & paste the code below in a file called MetaUML.php and place it in your extensions directory of your MediaWiki folder.
  3. Add "/ptmr8r /NimbusRomNo9L-Regu ;" (spaces and all) to Fontmap.GS in /usr/share/ghostscript/Version/Resource/Init/Fontmap.GS
  4. Put this line near the end of your LocalSettings.php in the MediaWiki root-folder to include the extension.
    require_once("$IP/extensions/MetaUML.php");
    
  5. Create the dirs Mediawiki Root/tmp"" and Mediawiki Home/math"" and make it writable by apache user

Gentoo [edit]

  1. emerge -av imagemagick ghostscript texlive texlive-metapost texlive-fontsrecommended
    
  2. cp MetaUML.php Mediawiki_Root/extensions
    
  3. echo "/ptmr8r /NimbusRomNo9L-Regu       ;" >> /usr/share/ghostscript/GS_Version/Resource/Init/Fontmap.GS
    
  4. echo "require_once('extensions/MetaUML.php')">> Mediawiki Root/LocalSettings.php
    
  5. mkdir Mediawiki_Root/images/tmp Mediawiki_Root/images/math
    
  6. chown apache:apache Mediawiki Root/images/tmp Mediawiki Root/images/math
    
  7. chmod 700 Mediawiki_Root/images/tmp Mediawiki Root/images/math
    

Code [edit]

Version 0.4 [edit]

<?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 ImageMagic 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.exe";
$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;
 
      $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 occured in MetaUML extension]";
  } else {
    $text = "<img src='$url'>";
  }
 
  return $text;
}

Version 0.4.0 for Unix/Linux [edit]

There is another version that works with a UNIX system at /Code 0.4.0 unix.

  • all \ has been coverted in /
  • executables corrected for unix --Zioalex 16:50, 4 November 2009 (UTC)

See also [edit]