Administration système Unix et divagations diverses

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 8 septembre 2011

PDF::API2 en CGI et "malformed xref"

PDF::API2 est un module perl pour la manipulation de fichiers PDF. Il peut être utilisé en combinaison avec un script CGI pour envoyer un fichier directement à un client. Quelque chose du genre :

use PDF::API2;
use CGI;

my $cgi = CGI->new;
my $pdf = new PDF::API2();
# …
print $cgi->header(-type => 'application/pdf', -Content_Disposition => 'attachment; filename=monpdf.pdf');
# Envoie le PDF sur la sortie standard (vers le client)
$pdf->saveas('-');

Le PDF ainsi généré pourra être ouvert par des lecteurs basés sur libpoppler (et peut être d'autres) mais Acrobat Reader refusera en prétendant qu'il est corrompu. En essayant de rouvrir le même PDF avec PDF::API2, celui-ci vous enverra gentiment bouler avec un Malformed xref in PDF file at /usr/share/perl5/PDF/API2/Basic/PDF/File.pm line 1198..

En fait, les sections xref des PDF utilisent des informations comprenant des déplacements dans le fichier. Pour les obtenir, PDF::API2 utilise le déplacement courant du fichier dans lequel il est en train d'écrire. Le problème est que lorsque l'on est en CGI, l'écriture des headers décale le déplacement courant de la taille de ceux-ci, les déplacement indiqués dans la XRef sont donc invalides.

Pour résoudre le problème, il suffit de modifier légèrement la génération du PDF en l'écrivant dans une chaine puis en l'affichant :

# $pdf->saveas('-');
print $pdf->stringify();

Et l'erreur disparaît, Acrobat Reader est content…

mardi 6 septembre 2011

Timeout avec GTKmm

Petit extrait de code pour créer un timeout avec GTKmm. À adapter proprement pour l'utilisation.

// Variable globale (sale) pointant sur le timeout
Glib::RefPtr<Glib::TimeoutSource> ts;

// Définition du callback
bool timeout() {
  std::cerr << "Callback timeout" << std::endl;
  // Détruit le timeout, évitant de futures notifications
  ts->destroy();
}

// ...

// le callback sera appelé toutes les 500ms environ (dans la mainloop Gtk)
ts = Glib::TimeoutSource::create(500);
// Indique le callback à appeler
ts->connect(sigc::ptr_fun(&timeout));
// Attache la source au contexte ce qui déclenche
// l'exéccution périodique du callback à partir de l'entrée dans la mainloop
ts->attach();

// ...

mardi 23 août 2011

Améliorer l'affichage de SVN diff

Parce que quand on a goûté à Git, quand même, c'est dur…

Lire la suite...

mercredi 9 mars 2011

Dojotoolkit - Instanciation par programmation de NumberTextBox/CurrencyTextBox

Juste un petit post rapide parce que ça m'a pris pas mal de temps à trouver d'où venait le problème.

Si vous utilisez Dojo, vous essayez peut être d'améliorer les performances en ne passant pas par leur parser (qui analyse tout le DOM) mais en instanciant directement les widgets.

Je suis tombé récemment sur un problème avec des dijit.form.CurrencyTextBox (mais j'imagine qu'il est également valable pour les NumberTextBox) que j'initialise à partir d'input qui ont une valeur. Le widget résultant ne mettait pas en forme la valeur du contrôle avant que l'on lui donne le focus et qu'on le quitte. Pire encore, si la locale n'était pas en-us on se retrouvait avec un message d'erreur "valeur invalide" (en raison de l'utilisation du point décimal à la place de la virgule. Par contre, le même input avec un dojoType passé à dojo.parser.instantiate s'affichait correctement du premier coup.

La solution est toute simple, il suffit de forcer la conversion de la valeur en Number : <code> var field = new dijit.form.NumberTextBox({ value: Number(i.value) }, i); field.startup(); </code>

Si jamais i.value n'est pas un nombre ou est vide, Number(i.value) renverra NaN qui est très bien accepté par le constructeur. En espérant vous avoir fait gagner un peu de temps...