Open main menu

Changes

article about integrating inline context rendering
= Integrating ConTeXt in Mediawiki Software =

The contextgarden.net wiki was enhanced in several ways to serve
better for the needs of documenting ConTeXt. One way is the inline
rendering of ConTeXt code.

== Inline processing of ConTeXt code ==
The user of the contextgarden.net wiki can put ConTeXt code between
the wiki-tags <nowiki><context>...</context></nowiki>, such as:
<pre>
<nowiki>
<context>
This is \ConTeXt\ code.
</context>
</nowiki>
</pre>

This will be rendered directly by ConTeXt and the result (more
precisely: a bitmap of the result) will be displayed in the webbrowser
instead of the input. To achieve this, I have created a little
extension that I document here.


In <tt>LocalSettings.php</tt> the wiki-software loads the extension:

<pre>
if(file_exists("localext/texshowwiki.php")) {
include_once("texshowwiki.php");
} else {
error_log("texshowwiki.php not loaded",0);
}
</pre>

the extension is (you see it) in <tt>localext/texshowwiki.php</tt>.
The name is a bit misleading, it is historic. Let's take a look at the
extension:

<pre>
<?php
require_once( "wikitex.php");
$wgExtensionFunctions[] = 'TW_Register';

function TW_Register()
{
global $wgParser;
$wgParser->setHook( 'context', 'TW_show_context' );
}

function TW_show_context($string) {
return wikitex($string);
}

?>
</pre>

First we define a new hook. When the mediawiki parser encounters the
new tag 'context', it should feed the contents of the text that is
enclosed in the <nowiki><context>...</context></nowiki> tags to the
method <tt>TW_show_context</tt>. This is what the file
"wikitex.php" looks like:

<pre>
<?php
function wikitex($inputstring) {
require("contextpng.php");
// needs iconv compiled in php!!
$somestring = iconv( "UTF-8","ISO-8859-1", $inputstring);
$md5=md5($somestring);

$destfile=$imagedir ."/". $md5 .".png";
$ret = "<img src=\"/wikiteximage/" . $md5 . ".png\" />";

if (!file_exists($destfile)) {
$towrite="\\starttext\n" . $somestring . "\\stoptext ";
$path=getenv('PATH');
putenv("PATH=$path:" . $texpath);

if (!file_exists($maindir)) {
mkdir($maindir, 0777);
}
if (!file_exists($imagedir)) {
mkdir($imagedir, 0777);
}

$tempdir=rtrim(`$mktemp`) ;
$filename = $tempdir . "/wikitex.tex";

if (is_writable ($tempdir )) {
if (! $handle =fopen ($filename ,'a' )) {
error_log("Cannot open file ($filename)") ;
return "(internal error: cannot open file $filename)";
}
if ( fwrite ($handle ,$towrite ) === FALSE ) {
error_log ("Cannot write to file ($filename)") ;
return "internal error: cannot write to file $filename";
}
}
fclose ($handle);
if (! is_writable ($tempdir)) {
error_log ("The file $filename is not writable") ;
return "internal error: the file $filename is not writable";
}
$olddir=getcwd();

if (! chdir($tempdir)) {
error_log ("chdir error");
return "internal error: chdir failed";
chdir ($olddir);
}
system($texexec,$texret);
if ($texret == 0) {
system($pdfcrop,$cropret);
if ($cropret != 0) {
error_log ("pdfcrop error");
chdir ($olddir);
return "internal error: pdfcrop failed";
}
system($gs,$gsret);
if ($gsret != 0) {
error_log ("gs error");
chdir ($olddir);
return "internal error: gs failed";
}
system($convert,$convertret);
if ($convertret != 0) {
error_log ("convert error");
chdir ($olddir);
return "internal error: convert failed";
}
if (! copy("cropped.png",$destfile)) {
error_log ("copy error");
chdir ($olddir);
return "internal error: copy error";
}
} else {
error_log ("texexec error") ;
$ret= "(texexec error, something is wrong with the input)";
}
chdir ($olddir);
}


return $ret ;
}
?>
</pre>

The file <tt>contextpng.php</tt> defines some constants which are not
important now (see below). First, I calculate a checksum for the input
string. This is used to create a unique filename for each possible
input. If we already have a bitmap with this name, we know that the
input has not changed and we can display the image without
re-rendering the contents. If there is no filename with that checksum,
we have to render the contents. Now we write the contents into a file,
surrounded by <tt>\starttext...\stoptext</tt>. Then we run
texexec, pdfcrop, ghostscript and convert to generate and process the
image. To see which commands are used, here is the contents of the
file <tt>contextpng.php</tt>:

<pre>
<?php
$texpath="/opt/tetex/current/bin/i686-pc-linux-gnu";
$maindir="/tmp/wikitex";
$mktemp="/bin/mktemp -d -p $maindir XXXXXX" ;
$texexec="/opt/context/current/bin/texexec --nonstop --batch --environment=env-empty wikitex.tex > output 2>&1";
$pdfcrop="/opt/local/bin/pdfcrop --pdftexcmd=pdfetex --gscmd=/opt/gs/8.14/bin/gs wikitex.pdf cropped.pdf >/dev/null 2>&1";
$gs="/opt/gs/8.14/bin/gs -sOutputFile=dcropped.png -r300 -dTextAlphaBits=4 -sDEVICE=png256 -dBATCH -dNOPAUSE cropped.pdf >/dev/null 2>&1";
$convert="/usr/bin/convert -blur 0.20 -scale '50%' dcropped.png cropped.png";
$imagedir= $_SERVER["DOCUMENT_ROOT"] . "/wikiteximage";
?>
</pre>

That's it. All the mediwiki software passes back to the user is a
reference to the image (<tt><nowiki>"<img
src="/wikiteximage/<md5string>.png" />"</nowiki></tt>). The rest is
done behind the scenes.

More questions? Please contact pg&lt;at&gt;contextgarden.net and I'll
update this page.