2009-12-23 Enscript et l'utf-8

Dernière modification

Résumé : Comment faire avaler de l'utf-8 à Gnu-Enscript (un utilitaire qui convertit du texte brut en données PostScript) avec plus ou moins de bonheur.

Ajouté(e) :

> Tags: PlanetLibre, utilitaires, troubles in paradise

Modifié(e) :

< Tags: PlanetLibre, utilitaires, troubles in paradise,

à

> [[http://commons.wikimedia.org/wiki/File:Lord_Stanhopes_Printing_Press.jpg Wikimedia]]


http://upload.wikimedia.org/wikipedia/commons/3/39/Lord_Stanhopes_Printing_Press.jpg Wikimedia

Ce qui suit parle de Gnu-Enscript1, un utilitaire qui convertit du texte brut en données PostScript, ce qui permet de maîtriser finement le résultat d'impression.

Pour la première fois depuis des années, j'ai voulu imprimer un e-mail, à partir de Mutt... et ça n'a pas fonctionné! Il faut dire que dans cet intervalle, j'ai passé quelques années sans imprimante, et migré de la Slackware 10.0 ou 11 (?) à Debian Etch, puis Lenny, et bien sûr, les choses ont quelque peu évolué entretemps...

On précise à Mutt comment imprimer les e-mails via une directive de son fichier de configuration. Dans mon cas, c'était:

 set print_command="/usr/bin/enscript --word-wrap -Email \
    --header='Imprimé le %E à %C ||Page $%/$=' "

Dans le cas présent, le fichier de configuration indique à enscript d'imprimer en repliant les lignes trop longues à l'endroit des espaces, en effectuant un formattage spécifique aux e-mails, avec un en-tête personnalisé indiquant la date d'impression et une numérotation des pages de la forme "Page 1/2".

Le formattage spécifique aux mails est un cas particulier de source highlighting (traduire par «mise en évidence de la syntaxe» ?) offert par enscript. La plupart des langages de programmation sont par ailleurs supportés.

Mais donc, ça ne fonctionnait plus...

Premier problème, constaté en utilisant enscript en ligne de commande, la commande lpr a été détronée au profit de lp. Or enscript s'attend toujours à pouvoir recourir à la première:

  gv@fantasio:~$ enscript test.txt 
  sh: lpr: command not found

Une recherche sur le site http://packages.debian.org 2 permet de voir que la commande lpr est encore disponible dans le paquet cups-bsd, qui «fournit les commandes BSD pour interagir avec CUPS. Il est fourni séparément pour autoriser la coexistence de CUPS avec d'autres systèmes d'impression (dans une faible mesure).».

J'aime assez le «dans une faible mesure»...

Ça serait une piste, mais comme j'hésite toujours à installer des paquets quand ils ne sont pas vraiment nécessaires, j'attends un peu. Il y a aussi le paquet cruft3 qui «examine votre système pour y trouver les choses qui y sont, mais qui ne devraient pas, ainsi que celles qui n'y sont pas, mais devraient y être». Je me dis que quand on commence à creuser dans un système Linux, on fait parfois des rencontres bizarres, mais il n'est pas vraiment clair que ce paquet fournit également les services liés à une commande manquante, donc je m'abstiens.

En fin de compte, la solution résidait dans enscript lui-même, parce que la création d'un fichier de préférence permet de spécifier le programme à qui l'impression est confiée, via une option Spooler. On peut également préciser le switch permettant de choisir l'imprimante, ce qui sera nécessaire puisqu'avec lpr, c'était -P tandis qu'avec lp, c'est -d (rien n'est simple).

  gv@fantasio:~$ cat .enscriptrc
  QueueParam: -d
  Spooler: lp

C'est une première chose de réglée.

Second problème, plus délicat, enscript ne traite pas les textes encodés en utf-8.

Pour continuer à utiliser enscript, il sera donc nécessaire de convertir les textes bruts qui lui seront confiés. À titre de test, je remplace la directive relative à la commande d'impression par ceci:

  set print_command="cat > /home/gv/test"

ce qui permet de constater que les données que ma version de Mutt envoie à l'impression sont bien encodées en utf-8, quel que soit celui du message.

Il y a le choix entre iconv et recode; je n'ai pas comparé dans le détail ces utilitaires, je me suis arrêté au premier parce que sa syntaxe me semblait plus intuitive.

On peut donc continuer à se servir d'Enscript sans qu'il soit nécessaire d'enregistrer à chaque fois une seconde version du fichier d'origine - encodée en latin1 - puisque les deux programmes peuvent interagir via leurs entrées et sorties standards:

  $ iconv -f utf8 -t latin1 texte.txt | enscript -o texte.ps

La directive dans .muttrc devient donc:

  set print_command="  iconv -f utf-8 -t latin1 |\
     usr/bin/enscript --word-wrap -Email -d PDF  \
     --header='Impr. le %D{%a. %d/%m/%Y} - %C ||Page $%/$='

Le format d'en-tête est un peu modifié au passage. La présence de caractères utf-8 à cet endroit était aussi problématique, et ne pouvait être résolu de la même manière. J'ai préféré retirer le nom du mois et toute présence de caractère accentué. Et j'ai aussi choisi une imprimante virtuelle PDF au lieu de l'imprimante physique.

Pour l'impression de mes mails, les choses sont donc rentrées dans l'ordre...

http://www.k1ka.be/pics/mail.gif

...mais j'aurais aimé trouvé une solution globale qui m'aurait permis d'utiliser enscript sans plus avoir à penser à ces histoires d'encodage.

Enscript dispose d'une option permettant de filtrer les fichiers qui lui sont transmis au moyen de n'importe quelle commande. La page de manuel donne comme exemple

    enscript --filter="cat %s | tr ’a-z’ ’A-Z’" foo.c

J'avais donc créé comme filtre un petit script 2latin1.sh qui détermine l'encodage du texte au moyen de la commande file:

  gv@fantasio:~$ cat bin/2latin1.sh 
  #!/bin/bash
  
  FILE=$1
  FILETYPE=$(file -bi $FILE)
  ENCODING=${FILETYPE##*charset=}
  
  case "$ENCODING" in
    iso-8859-1    ) cat $FILE ;;
    *             ) iconv -f $ENCODING -t latin1 $FILE ;;
  esac

avec l'idée de créer un alias pour enscript:

  gv@fantasio:~$ alias enscript='enscript --filter="2latin1.sh %s" '

À première vue, ça fonctionne... Malheureusement, je découvre alors (il faudrait toujours lire attentivement la page de manuel) que les options --filter et --highlight ne sont pas compatibles, c-à-d. que le filtre n'est pas appliqué lorsqu'on veut mettre la syntaxe en évidence :-(. C'est perdre une des fonctionnalités les plus intéressantes d'enscript.

D'un autre côté, il est rare que j'ai besoin du source highlighting, si ce n'est pour imprimer les mails...

Me basant sur la solution qui existe sur (Open)Suse4 je tente quelque peu de créer un wrapper, un script nommé enscript qui transmettrait la tâche au binaire qui, lui, serait renommé enscript.bin.

Mais c'est moins trivial qu'il ne semble. Enscript peut accepter en arguments plusieurs fichiers à traiter, ainsi que des données sur l'entrée standard.

En fin de compte, pour la raison évoquée plus haut, je me contenterai de l'alias et du filtre, j'ai toujours la possibilité de recourir au chemin complet pour un besoin ponctuel.

Une ébauche de wrapper

  #!/usr/bin/perl
  use strict;
  
  my $file =  pop(@ARGV);
  
  if (-e $file) { 
    my $filetype = `file -ib $file`; 
    $filetype =~ /charset=(.*)$/; # file -ib renvoie "text/plain charset=xxxx"
        my $encoding = $1;
    if ($encoding =~ /iso-8859-1/) {
      open(TEXT, "<", $file);
    } else {
      open(TEXT, "iconv -f $encoding -t latin1 $file |");
    }
    open(ENSCRIPT, "|/usr/bin/enscript @ARGV"); 
    while (<TEXT>) {
      print ENSCRIPT;
    }  
    close (TEXT);
    close (ENSCRIPT);
  } else {
    # si le dernier argument n'est pas un nom de fichier
    # on suppose que les données sont transmises via 
    # l'entrée standard
    print "Utiliser plutôt /usr/bin/enscript :-)\n"
  }
  

Réflexions en vrac pour conclure

Footnotes:

1. GNU Enscript is a free replacement for Adobe's enscript program. http://www.gnu.org/software/enscript/
2. On peut rechercher dans le contenu des paquets, ce qui revient à taper l'url http://packages.debian.org/search?searchon=contents&keywords=lpr&mode=path&suite=stable&arch=any
3. Paquet : cruft (0.9.12) Find any cruft built up on your system http://packages.debian.org/lenny/cruft
4. J'ai récupéré un paquet rpm disponible par exemple ici pour en extraire le script, fort complexe. Il semble bien sous GPL, comme le reste du paquet. Mais je n'ai jamais réussi à le faire fonctionner correctement. D'autres seront peut-être plus heureux que moi.
5. paps - A Pango to PostScript converter http://paps.sourceforge.net/