Tutoriel - écrire un plugin Orangium: conversion html vers pdf
À l'approche de notre arrivée dans le monde du logiciel libre, nous savons qu'il manque quelque peu de documentation sur nos procédés...
Ce tutoriel est une des étapes dans notre effort d'ouverture. Il s'adresse avant tout à un public technique de développeurs C#, qui auraient besoin d'étendre le moteur d'Orangium pour leurs applications. Je vais détailler les étapes de création d'un projet sous Visual Studio. Si vous voulez utilisez autre chose... bien à vous ! N'hésitez pas à nous poser des questions, nous y répondrons autant et aussi vite que possible.
L'exemple traité ici va être assez simple car il n'aura que peu d'interactions avec le core. Pas d'interfaces d'administrations, juste quelques paramètres à ajouter sur le serveur.
Notre sujet : la conversion HTML vers PDF et image. Commençons !
Pourquoi un plugin ?
Parce que nous allons nous baser sur ce qui se fait de mieux pour le rendu HTML, soit une librairie externe basée sur Webkit (wkhtmltopdf). De fait, nous ne voulons pas obliger ceux qui n'ont pas besoin de cette fonctionnalité à installer ce logiciel sur leurs serveurs, et il est donc logique d'en externaliser les fonctionnalités. Orangium core contient tout ce qu'il faut pour accéder facilement à des fonctionnalités externes. Nous allons bientôt voir comment tout cela fonctionne ! (Record du monde d'utilisation du mot « fonctionnalité » battu...)
Comment un plugin ?
Accrochez-vous on commence ! Nous allons voir comment écrire un plugin standalone, sans ouvrir toute la solution Orangium mais en créant un simple projet externe. Ouvrez Visual Studio et créez un nouveau projet de librairie de classe (ici en screenshot version 10)
Cliquez OK. Une fois l'environnement ouvert, renommez le fichier Class1.cs en ce que vous voulez (j'ai mis ici Renderer.cs, ça fait bien et ça va pas mal avec le nom du plugin). Cette opération renomme également la classe dans le fichier, c'est plus pratique. Rendus là, quelques modifications sont à apporter aux propriétés du projet ainsi créé :
Tous les DLL externes qu'on veut pouvoir appeler à partir d'Orangium DOIVENT correspondre à ce schéma de nommage. Nous chargeons les DLL par Reflection et les méthodes sont ensuite recherchées dans deux namespace seulement : Orangium.Plugin et Orangium.Engine. Bref, c'est comme ça que ça fonctionne et on vous dira si ça change.
Ensuite, nous allons copier le code de MGOwen, disponible ici et en licence CC. Quelques modifications mineures sont à faire cependant :
-
ajouter les directives using manquantes :
- using System.IO ;
- using Orangium.Engine ;
- ajouter la référence à Orangium.Engine (clic droit sur les références du projet, ajouter référence et browser jusqu'à trouver le graal). En l'occurrence, ça nous sert peu, mais c'est pour remplacer les appels à System.Configuration (nous avons notre propre wrapper qui cast tout comme on aime)
- changer les appels à ConfigurationManager (ConfigurationManager.AppSettings[...) à AppSettings.String("setting_name"), qui est notre methode core pour accéder aux valeurs de configuration.
- changer le working directory du processus à lancer à Directory.GetCurrentDirectory(); (d'où l'ajout de System.IO dans les using)
- Ajouter l'attribut [Init("",AllowReflectionCall: true)] pour dire à nos batch de mise à jour d'ajouter cette méthode à celles que l'on a le droit d'appeler en Reflection
- using System.IO;
- using Orangium.Engine;
- namespace Orangium.Plugin
- {
- public class Renderers
- {
- /// Convert Html page at a given URL to a PDF file using open-source tool wkhtml2pdf
- ///
- ///
- ///
-
///
- [Init("",true)]
- public static bool HtmlToPdf(string Url, string outputFilename)
- {
- // assemble destination PDF file name
- string filename = AppSettings.String("ExportFilePath") + "\\" + outputFilename + ".pdf";
- var p = new System.Diagnostics.Process();
- p.StartInfo.FileName = AppSettings.String("HtmlToPdfExePath");
- string switches = "--print-media-type ";
- switches += "--margin-top 4mm --margin-bottom 4mm --margin-right 0mm --margin-left 0mm ";
- switches += "--page-size A4 ";
- switches += "--no-background ";
- switches += "--redirect-delay 100";
- p.StartInfo.Arguments = switches + " " + Url + " " + filename;
- p.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output
- p.StartInfo.RedirectStandardOutput = true;
- p.StartInfo.RedirectStandardError = true;
- p.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none
- p.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory(); //(p.StartInfo.FileName);
- p.Start();
- // read the output here...
- string output = p.StandardOutput.ReadToEnd();
- // ...then wait n milliseconds for exit (as after exit, it can't read the output)
- p.WaitForExit(60000);
- // read the exit code, close process
- int returnCode = p.ExitCode;
- p.Close();
- // if 0 or 2, it worked (not sure about other values, I want a better way to confirm this)
- return (returnCode == 0 || returnCode == 2);
- }
- }
- }
Bon, on devrait être à peu près clair rendus là. Le projet complet est disponible en document attaché avec l'article.
Utilisez votre plugin !
Une fois l'objet de votre désir compilé, la vie est somme toute fort simple. Ajouter deux œufs et battez fort, avec un peu d'huile d'olive et d'ail et vous avez un bel aïoli !
Désolé :P
Ajoutez donc votre DLL dans le répertoire bin de votre site web, puis lancez update.bat. Ce fichier va s'occuper d'enregistrer vos nouvelles méthodes en base de données, les rendant ainsi accessible à vos bons offices.
Nous pouvons donc maintenant appeler notre nouvelle méthode en Reflection, aussi bien par la Query String que directement dans le code via la methode Action.Execute si bien nommée.
Aller plus loin, plus haut, plus fort
Concrètement, on ne veut pas rendre cette opération accessible via une interface web... Pour nous en tout cas. Un peu dangereux pour nos serveurs tout de même... Mais mettons que ça vous intéresserait de proposer un système pour pondre du PDF à partir de code HTML à vos utilisateurs, gang de fous. Pour la démo, je vous montrerai comment faire dans un prochain tutoriel... ça ou quelque chose d'approchant, peut-être un plugin complet avec ses pages dans l'interface d'administration et ses propres tags/options de formulaires spécifiques.
Disclaimer
L'écriture d'un tutoriel est une grande première pour Orangium et pour moi, ainsi que l'envoi de notre sacro saint Orangium.Engine.dll sur le web sauvage... Tous vos commentaires sont donc bienvenus ! Et n'essayez pas cet ersatz de recette d'aïoli surtout !














Commentaires