Wikini

FormulesTeXDansWikiNi

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-54-146-154-243.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 ($contents, 0, 1);
      if (($retval == "C") || ($retval == "M") || ($retval == "L")) {
    if ($retval == "C")
      $conservativeness = 2;
    else if ($retval == "M")
      $conservativeness = 1;
    else
      $conservativeness = 0;
    $outdata = substr ($contents, 33);

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

    $outhtml = substr($outdata, 0, $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 ($contents, 33);
    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 ($contents, 33);
    $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($contents, 1)."): "
      .wfEscapeHTML($tex)."</h3>";
      }

      $outmd5 = substr ($contents, 1, 32);
      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+|".



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]