Wikini

FormulesTeXDansWikiNi

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-54-196-2-131.compute-1.amazonaws.com

Inclusion de formules TeX/LaTeX


La technique par génération d'images

Solution de WikiMedia?

En s'inspirant beaucoup de Mediawiki, le moteur de WikiPedia, on peut supporter simplement les formules TeX. Suivant que la formule est simple (i_2) ou compliquée (\sum_i...), le rendu se fera en HTML directement, ou sous la forme d'une image png (installation LaTeX requise côté serveur). J'ai repris mediawiki dans wikini pour supporter ce genre d'écritures : \( i_2 \), et \[ i_2 \]. Le premier est associé à une classe CSS "math_inline", le second "math_center", pour pouvoir émuler la mise en page LaTeX. Dernier détail : il y a un mécanisme de cache pour stocker les images/codes html générés pour accélérer le chargement des pages.

Exemple

Marche à suivre :
<?
/*
 * Almost entirely taken from mediawiki :
 *  http://cvs.sourceforge.net/viewcvs.py/wikipedia/phase3/includes/
 */

if (!function_exists("wfEscapeHTML"))
{
  function 
wfEscapeHTML$in )
    {
      return 
str_replace(
             array( 
"&""\""">""<" ),
             array( 
"&amp;""&quot;""&gt;""&lt;" ),
             
$in );
    }
}

if (!
function_exists("linkToMathImage"))
{
  function 
linkToMathImage ($wgMathPath$tex$outputhash )
    {
      global 
$wiki;
      return 
"<img src=\"".$wgMathPath."/"
    
.$outputhash.$wiki->config["ghostscript_png_ext"]
    .
"\" alt=\"".wfEscapeHTML($tex)."\">";
    }
}


if (!
function_exists("renderMath"))
{
  function 
renderMath$tex )
    {
      global 
$wiki;
      
$mf   "math_failure";
      
$munk "math_unknown_error";

      
$math_dir_url $wiki->config["math_dir_url"];
      
$math_dir_sys $wiki->config["math_dir_sys"];
      
$math_tmp_dir $wiki->config["math_tmp_dir"];
      
$math_inputenc $wiki->config["math_inputenc"];
      
$math_render_type $wiki->config["math_render_type"];
      
/*    0 : "Toujours produire une image PNG",
            1 : "HTML si tres simple, autrement PNG",
            2 : "HTML si possible, autrement PNG",
            3 : "Laisser le code TeX original",
            4 : "Pour les navigateurs modernes" (mathml) */
      
if ($math_render_type == 3)
    return (
'$ '.wfEscapeHTML($tex).' $');

      
$md5 md5($tex);
      
$md5_sql mysql_escape_string(pack("H32"$md5));
      if (
$math_render_type == 0)
    
$sql "SELECT math_outputhash FROM ".$wiki->config["table_prefix"]
      .
"math WHERE math_inputhash = '".$md5_sql."'";
      else
    
$sql "SELECT math_outputhash,math_html_conservativeness,math_html FROM ".$wiki->config["table_prefix"]."math WHERE math_inputhash = '".$md5_sql."'";

      
$res $wiki->Query($sql);

      if( 
$rpage mysql_fetch_object$res ) ) {
    
$outputhash unpack"H32md5",
                  
$rpage->math_outputhash
                  
"                " );
    
$outputhash $outputhash ['md5'];
    if( 
file_exists"$math_dir_sys/$outputhash"
             
.$wiki->config["ghostscript_png_ext"] ) )
      {
        if ((
$math_render_type == 0)
        || (
$rpage->math_html == '')
        || ((
$math_render_type == 1)
            && (
$rpage->math_html_conservativeness != 2))
        || ((
$math_render_type == 4)
            && (
$rpage->math_html_conservativeness == 0)))
          return 
linkToMathImage $wiki->config["math_dir_url"],
                       
$tex$outputhash );
        else
          {
        return 
$rpage->math_html;
          }
      }
      }

      
$cmd $wiki->config["math_texvc_path"]." "
    
.escapeshellarg($math_tmp_dir)." "
    
.escapeshellarg($math_dir_sys)." "
    
.escapeshellarg($tex)." ".escapeshellarg($math_inputenc);
      echo 
$cmd;
      
$contents = `$cmd`;

      if (
strlen($contents) == 0)
    return 
"<b>".$mf." (".$munk." 1): ".wfEscapeHTML($tex)."</b>";
      
$retval substr ($contents01);
      if ((
$retval == "C") || ($retval == "M") || ($retval == "L")) {
    if (
$retval == "C")
      
$conservativeness 2;
    else if (
$retval == "M")
      
$conservativeness 1;
    else
      
$conservativeness 0;
    
$outdata substr ($contents33);

    
$i strpos($outdata"\000");

    
$outhtml substr($outdata0$i);
    
$mathml substr($outdata$i+1);

    
$sql_html "'".mysql_escape_string($outhtml)."'";
    
$sql_mathml "'".mysql_escape_string($mathml)."'";
      } else if ((
$retval == "c") || ($retval == "m") || ($retval == "l"))  {
    
$outhtml substr ($contents33);
    if (
$retval == "c")
      
$conservativeness 2;
    else if (
$retval == "m")
      
$conservativeness 1;
    else
      
$conservativeness 0;
    
$sql_html "'".mysql_escape_string($outhtml)."'";
    
$mathml '';
    
$sql_mathml 'NULL';
      } else if (
$retval == "X") {
    
$outhtml '';
    
$mathml substr ($contents33);
    
$sql_html 'NULL';
    
$sql_mathml "'".mysql_escape_string($mathml)."'";
    
$conservativeness 0;
      } else if (
$retval == "+") {
    
$outhtml '';
    
$mathml '';
    
$sql_html 'NULL';
    
$sql_mathml 'NULL';
    
$conservativeness 0;
      } else {
    if (
$retval == "E")
      
$errmsg wfMsg"math_lexing_error" );
    else if (
$retval == "S")
      
$errmsg wfMsg"math_syntax_error" );
    else if (
$retval == "F")
      
$errmsg wfMsg"math_unknown_function" );
    else
      
$errmsg $munk." ".$retval;
    return 
"<h3>".$mf." (".$errmsg.substr($contents1)."): "
      
.wfEscapeHTML($tex)."</h3>";
      }

      
$outmd5 substr ($contents132);
      if (!
preg_match("/^[a-f0-9]{32}$/"$outmd5))
    return 
"<b>".$mf." (".$munk." 3): ".wfEscapeHTML($tex)."</b>";

      
$outmd5_sql mysql_escape_string(pack("H32"$outmd5));

      
$sql "REPLACE INTO ".$wiki->config["table_prefix"]."math VALUES ('"
    
.$md5_sql."', '".$outmd5_sql."', ".$conservativeness.", ".$sql_html
    
.", ".$sql_mathml.")";
    
      
$res $wiki->Query($sql);
# we don't really care if it fails

    
if (($math_render_type == 0) || ($rpage->math_html == ''
            || ((
$math_render_type == 1) && ($conservativeness != 2))
            || ((
$math_render_type == 4) && ($conservativeness == 0)))
        return 
linkToMathImage($wiki->config["math_dir_url"],
                                   
$tex$outmd5);
    else
        return 
$outhtml;
  }
}

echo 
renderMath($text);
?>

/* Chemin HTTP pour math_img */
    "math_dir_url" => "/wikini/math_img",

        /* Chemin système pour math_img */
    "math_dir_sys" => "/var/httpd/htdocs/wikini/math_img",

        /* Chemin système vers l'exécutable texvc */
    "math_texvc_path" => "/var/httpd/htdocs/wikini/formatters/texvc",

        /* Répertoire système pour les fichiers temporaires */
    "math_tmp_dir" => "/tmp",

    "math_inputenc" => "UTF-8",

    "math_render_type" => "1",
    /* Valeurs possibles pour math_render_type :
            0 : "Toujours produire une image PNG",
            1 : "HTML si tres simple, autrement PNG",
            2 : "HTML si possible, autrement PNG",
            3 : "Laisser le code TeX original",
            4 : "Pour les navigateurs modernes" (mathml) */

    "ghostscript_png_ext" => ".png",
    /* Valeurs possibles pour ghostscript_png_ext :
            Versions anciennes de ghostscript : ".png.0"
            Versions récentes de ghostscript : ".png" */

@@ -117,6 +119,26 @@
                {
                        return $matches[1];
                }
+                // \(math\)
+                else if (preg_match("/^[\\\\]\\((.*)[\\\\]\\)$/s",
+                                    $thing, $matches))
+                {
+                        $output = "<div class=\"math_inline\">";
+                        $output .= $wiki->Format(trim($matches[1]), "math");
+                        $output .= "</div>";
+
+                        return $output;
+                }
+                // \[math\]
+                else if (preg_match("/^[\\\\]\\[(.*)[\\\\]\\]$/s",
+                                    $thing, $matches))
+                {
+                        $output = "<div class=\"math_center\">";
+                        $output .= $wiki->Format(trim($matches[1]), "math");
+                        $output .= "</div>";
+
+                        return $output;
+                }
                // code text
                else if (preg_match("/^\%\%(.*)\%\%$/s", $thing, $matches))
                {
@@ -278,6 +300,8 @@
 $text = trim($text)."\n";
 $text = preg_replace_callback(
        "/(\%\%.*?\%\%|".
+        "[\\\\]\\[.*?[\\\\]\\]|".
+        "[\\\\]\\(.*?[\\\\]\\)|".
        "\"\".*?\"\"|".
        "\[\[.*?\]\]|".
        "\b[a-z]+:\/\/\S+|".

USE la_table_wikini; -- En général c'est tout simplement "wikini" ici
CREATE TABLE `wikini_math` (
  `math_inputhash` varchar(16) NOT NULL default '',
  `math_outputhash` varchar(16) NOT NULL default '',
  `math_html_conservativeness` tinyint(1) NOT NULL default '0',
  `math_html` text,
  `math_mathml` text,
  UNIQUE KEY `math_inputhash` (`math_inputhash`)
);

div.math_inline { display: inline; }
div.math_center { text-align: center; }


Et voilà.

-- DavidDecotigny

Solution de Spip: le mode client-serveur

Références:
Cette solution nécessite évidemment d'avoir accès à un serveur pour générer les images. Spip propose math.spip.org/tex.php mais idéalement il faudrait faire tourner le script sur un serveur dédié à WikiNi je pense...
NB.: la solution n'est pas encore adaptée à WikiNi, SpikiNi utilise le formateur de Spip, et il n'est donc pas possible de transposer directement le code sous WikiNi...
-- LordFarquaad

Proposition php pur


Je trouve que le fait de devoir utiliser un logiciel externe à php n'est vraiment pas pratique: non seulement cela ne fonctionne que sous GNU/Linux, mais en plus cela nécessite les droits d'exécution depuis php. En pratique il n'y a pratiquement aucun hébergeur qui accepte cela... (question de sécurité)
La solution à ce problème est une gestion complète via php. Au niveau de WikiNi, je pense que le mieux est la création d'une action, qui serait en même temps capable de générer l'image:

Autre possibilité: le MathML

Avantages

Le MathML présente de nombreux avantages par rapport à l'utilisation d'images, notamment:

Aspects techniques

La mise en oeuvre du MathML n'est pas une chose simple.

Problèmes


-- LordFarquaad



Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]