Publié dimanche 8 juin 2008 20:43 par Audrey

[WPF] Après le XPS, un petit lecteur de DOC et de PDF

Après le format XPS, voici la version DOC et PDF. Pour pouvoir générer des images à partir de ces types de documents, j'ai testé plusieurs bibliothéques gratuites et libres que l'on peut trouver en cherchant sur Internet. Après plusieurs tests infructueux, j'ai opté pour l'utilisation des composants COM de l'outil PDFCreator. Cette solution est un peu moins intuitive que celle utilisée pour les XPS, peu de documentation existe malheureusement pour manipuler au mieux ces objets COM, un petit exemple ici de documentation sur cet objet COM.

Voici le code que j'ai utilisé afin de pouvoir traiter les documents DOC et les PDF.

Tout d'abord, l'activation d'une instance de l'objet COM de PDFCreator :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string parameters;
pErr = new PDFCreator.clsPDFCreatorError();

_PDFCreator = new PDFCreator.clsPDFCreator();

_PDFCreator.eError += new PDFCreator.__clsPDFCreator_eErrorEventHandler(_PDFCreator_eError);
_PDFCreator.eReady += new PDFCreator.__clsPDFCreator_eReadyEventHandler(_PDFCreator_eReady);

parameters = "/NoProcessingAtStartup";


// ouverture de l'objet COM PDFCreator
if (!_PDFCreator.cStart(parameters, false))
{
System.Windows.MessageBox.Show("Attention", "PDFCreator est déjà ouvert !");
this.Close();
}

Ensuite, les options d'impression sont définies :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// option d'impression
opt = _PDFCreator.cOptions;
opt.UseAutosave = 1;
opt.UseAutosaveDirectory = 1;
opt.AutosaveDirectory = fi.DirectoryName;
opt.AutosaveFormat = FileTyp;
opt.AutosaveStartStandardProgram = 1;
opt.PNGColorscount = 1;
opt.OptionsVisible = 0;
opt.NoProcessingAtStartup = 1;
opt.AutosaveFilename = fname;
_PDFCreator.cOptions = opt;

_PDFCreator.cClearCache();

Puis, l'imprimante PDFCreator est définie comme l'imprimante par défaut :

1
2
3
                // définition de l'imprimante par défaut
DefaultPrinter = _PDFCreator.cDefaultPrinter;
_PDFCreator.cDefaultPrinter = "PDFCreator";

Le seul problème majeur que j'ai rencontré concerne les fichiers PDF. Lors du lancement de l'impression, la méthode d'impression de l'objet COM ouvre une instance du document PDF avec le logiciel approprié (dans mon cas il s'agit d'Adobe Reader). Et tant que l'utilisateur ne ferme pas manuellement le logiciel, le traitement du document est bloqué. J'ai identifié d'où venait le problème mais il faudrait que je modifie le code du composant COM et je n'en ai pas le temps et/ou les compétences pour le faire. Pour palier à cela, j'ai utilisé un pop-up pour avertir l'utilisateur de bien vouloir fermer le lecteur de PDF. Je sais que ce n'est pas la manière la plus élégante, et la plus transparente pour l'utilisateur, mais pour moi c'est celle qui fournira le moins de problèmes une fois mon projet fini (bientôt j'espère Wink). Si certains d'entre vous ont une solution je suis preneuse !

Ensuite l'impression peut commencer :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
                    // impression
_PDFCreator.cPrintFile(fi.FullName);

ReadyState = false;
_PDFCreator.cPrinterStop = false;


// attente jusqu'à la fin de l'impression
do
{
System.Windows.Forms.Application.DoEvents();

} while (!ReadyState && _PDFCreator.cProgramIsRunning);

                    _PDFCreator.cPrinterStop = true;


// retour de l'imprimante par défaut du départ
_PDFCreator.cDefaultPrinter = DefaultPrinter;

Enfin la méthode qui permet de fermer l'objet COM, lorsque l'impression est terminée :

1
2
3
4
5
6
7
8
9
10
11
12
        private void ClosePDFCreator()
{
// fermeture de l'objet COM PDFCreator
_PDFCreator.cClose();
System.Runtime.InteropServices.Marshal.ReleaseComObject(_PDFCreator);
System.Runtime.InteropServices.Marshal.ReleaseComObject(pErr);
pErr = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}

Pour l'affichage des images, j'ai utilisé le même WPFControlBook de Mitsu et le même user control UCBitmap qui m'avait permis d'afficher un Bitmap dans un control Image dans un application WPF, dont j'avais parlé dans un post précédent, sauf qu'ici ce sont des PNG que j'affiche :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        private void Window_Loaded(object sender, RoutedEventArgs e)
{
object itemPage;

try
{
// génération des images PNG
SaveDocPageToPng();


// ajout des images comme item du user control
for (int i = 1; i < pageCount; i++)
{
string source = FileName + i + ".png";
UCPng bt = new UCPng(source);

itemPage = (object)bt;
myBook.Items.Add(itemPage);
}
}
catch
{
ClosePDFCreator();
}
}

Voici la comparaison de disposition des pages, entre une lecture par défilement, et une lecture au format codex :

Comparaison DOC - WPF

Dans cet exemple, j'ai utilisé le format PNG pour la génération d'images, qui permet une plus grande compression des images que le BMP et donc les fichiers générés tiennent moins de place sur le disque dur. Par exemple, pour un document de 111 pages, en les générant en BMP j'obtiens un dossier pesant 690 Mo et en PNG seulement 5 Mo !

Pour conclure, le traitement avec des objets COM est un peu plus contraignant car il faut s'appuyer sur une application externe, en l'occurence PDFCreator, et il faut que l'utilisateur est cette application d'installée sur sa machine. Malgré tout je suis arrivée au but que je recherchais Smile.

(Pour l'exemple de document et de pdf, j'ai pris un ebook de William Shakespeare trouvé ici)

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Classé sous , ,

Les 10 derniers blogs postés

- [Silverlight] En attendant Silverlight 2 RTW par Blog Technique d'Audrey PETIT le il y a 21 heures et 22 minutes

- Le nouveau Gojira, c’est pour lundi… par CoqBlog le 10-11-2008, 01:18

- SharePoint : nouvel article sur la mise en place des Scopes dans MOSS Searchs par Blog Technique de Romelard Fabrice le 10-10-2008, 17:52

- Hello CS par Le Blog de julz le 10-10-2008, 12:26

- MSDN/TechNet/Microsoft Days Tour 2008 à Lille les 13 et 14 Octobre ! par RedoBlog - The .NET Gentleman !!! le 10-10-2008, 09:35

- MVC Pratique #07 - Un projet concret et le transfert des objets avec les ModelBinders par #Rui le 10-09-2008, 23:39

- SQL Server 2008 : Certifié - TS Admin (70-432) par SQL Server vu par Christian Robert le 10-09-2008, 10:58

- [WPF] Comment changer la couleur utilisée pour sélectionner les éléments d’un ItemsControl ? par Thomas Lebrun le 10-09-2008, 10:49

- Hello World! par Hamid's Place le 10-08-2008, 23:38

- SQL Profiler - Configuration pour un développeur - tracer les requêtes SQL de votre application par Atteint de JavaScriptite Aiguë [Cyril Durand] le 10-08-2008, 15:52