Archiv der Kategorie: Tutorials

Tutorials für Developers zu .NET. und Webentwicklung

Pdf-Dateien in Bitmaps zerlegen mit freier Software

In diesem Beitrag geht es um eine grundsätzlich einfache Anforderung: Ein Pdf-Dokument soll als Teil einer WPF-Anwendung seitenweise als Bitmap-Datei gespeichert werden, so dass sich z.B. eine einfache Seitenvorschau umsetzen lässt.

Natürlich gibt es jede Menge kommerzieller Komponenten, die alle sehr gut sind (ich verwende für ein Projekt z.B. Apose.Pdf for .Net, die ich empfehlen kann, auch wenn sie nicht ganz preiswert ist), und mit deren Hilfe sich die Anforderung in ein paar Zeilen Code umsetzen ließe. Für einen MVVM-Lehrgang ging es mir darum, keine kommerzielle Komponente verwenden zu müssen. Die Suche erwies sich als schwieriger als gedacht, denn die Anzahl freier Pdf-Tools ist mehr als überschaubar. Geht es um das Erstellen von Pdf-Dokumenten sind PdfSharp bzw. Migradoc eine sehr gute Wahl, allerdings bieten sie keine Renedering-Funktionalität.

Die offenbar einzige (!) freie Software, die Pdf-Dateien darstellen kann, ist muPdf von den Ghostscript-Entwicklern Artifex (https://mupdf.com). Der Sourcecode liegt in C vor, die Make-Datei erzeugt offenbar eine Exe-Datei, so dass das Einbinden in eine .NET-Assembly und Aufrufe per p/Invoke keine Option sind.

Zum Glück gibt es immer fleißige Entwickler, die solche Herausforderungen annehmen und anderen das Ergebnis ihrer Arbeit zur Verfügung stellen. Auf Codeproject gibt es zwei Projekte, die eine gute Grundlage für eigene Projekte sind:

1) https://www.codeproject.com/articles/498317/rendering-pdf-documents-with-mupdf-and-p-invoke-in

2) https://www.codeproject.com/Articles/579878/MoonPdfPanel-A-WPF-based-PDF-Viewer-Control

Im ersten Artikel beschreibt der Autor ausführlich, wie er in die von den Entwicklern von SumatraPdf, einem kleinen und feinen Open Source-Pdf-Betrachter, zur Verfügung gestellte muPdf-Bibliothek per p/Invoke einbindet.

Der zweite Artikel verwendet ebenfalls muPdf und macht daraus gleich ein Wpf-Control, das die Seiten eines Pdf-Dokuments anzeigen kann. Einfacher geht es fast nicht mehr.

Ich habe für mein Projekt eine andere Alternative verwendet in Gestalt des enorm vielseitigen Tools ImageMagick (z.B. http://imagemagick.sourceforge.net/http/www/windows.html).

Dieses Tool basiert auf Ghostscript, das daher zuvor installiert werden muss, und liegt als Exe-Datei vor. Es wandelt die Seiten einer Pdf-Datei in Bitmaps in einem beliebigen Format um. Auch wenn es grundsätzlich kein Problem mehr, die Exe-Datei als externen Prozess zu starten, etwas eleganter geht es mit Hilfe von Magick.Net, eine Assembly, die ImageMagick kapselt: https://magick.codeplex.com. Die Assembly kann auch per NuGet hinzugefügt werden. Auch hier muss Ghostscript zuvor installiert werden.

Das Abspeichern der Seiten einer Pdf-Datei als Bitmaps wird damit sehr einfach:

Ob sich diese Lösung auch für „echte“ Projekte eignet, bei denen sehr große Pdf-Dokumente geladen werden sollen, kann ich aktuell nicht beurteilen. Auf der seinen Seite wirkte mein Beispielprogramm etwas langsam und brach einem Versuch eine Pdf-Datei mit 420 Seiten zu laden mit einer OutOfMemoryExcception ab (allerdings hatte ich den Dpi-Wert auch auf 300 eingestellt, so dass jede einzelne Bitmap über 1 MB groß war). Kleinere Dateien mit ca. 40 Seiten werden schnell geladen. Auf der anderen Seite dürften die Entwickler von SumatraPdf dafür sorgen, dass die muPdf-Bibliothek performant genug ist, um auch mit großen Pdf-Dateien klarzukommen (das Laden der 420-Seiten-Datei in Sumatra Pdf ist kein Problem, sie wird praktisch verzögerungsfrei geladen).

Das Hauptausschlußkriterium für die Verwendung von muPdf und Ghostscript in einem Kundenprojekt dürfte das Lizenzmodell sein. Artifex beschreibt es ausführlich unter der folgenden Adresse: http://artifex.com/licensing/. Da es auf AGPL basiert (GNU Affero General Public License), müssste der Sourcecode der eigenen Anwendung veröffentlicht werden, was in der Regel nicht in Frage kommt. In den Lizenzbedingungen wird aber auch darauf hingewiesen, dass unter bestimmten Bedingungen auch eine Exe-Datei ausgeliefert werden darf. Wichtig ist, dass der Anwender erkennt, dass er oder sie muPdf und Ghostscript separat installieren.

Da ich alles andere als ein Experte für Lizenzierungsdetails bin und bei meinem Beispielen ohnehin immer der Quellcode dabei ist, ist dieser Aspekt für mich kein Thema. Für die meisten Entwickler dürfte das Lizenzmodell aber zu restriktiv bzw. „undurchsichtig“ sein (man kann natürlich bei Artifex nachfragen), so dass es am Ende wieder auf eine kommerzielle Komponente hinausläuft. Schade, dass Microsoft dieses Thema komplett ignoriert hat. Ein Pdf-Viewer als Teil des .NET Framework wäre eine natürlich sehr praktisch. Doch aller Voraussicht nach wird es dazu nie kommen.

Meine ersten Gehversuche mit AutoFac – Teil 1

In diesem Beitrag beschreibe ich meine ersten Gehversuche mit AutoFac, einem vielversprechenden DI-Container (DI = Dependency Injection).

Ich hatte in den vergangangen Jahren den sehr einfachen SimpleIOC-Contailer von Laurent Bugnion verwendet, der Teil von MVVM Light ist. Doch da ich MVVM Light seit einigen Jahren nicht mehr verwende und stattdessen die aus meiner Erfahrung sehr gute MVVM-Assembly von DevExpress (deren Kern nicht nur kostenlos, sondern auch quelloffen ist), habe ich auch SimpleIOC aus den Augen verloren.

Die wichtigste Frage natürlich vorweg: Wozu braucht man einen DI-Container?

Diese Frage ist gar nicht so einfach zu beantworten und sie ähnhelt der Frage, die Anfang der 90er Jahre of gestellt wurde. Wozu brauche ich diese Vererbung?

Schon damals hatte ich keine guten Antworten parat, außer dem üblichen „Sie führt einfach zu besser strukturiertem Code“. Aha. Bei DI ist es ähnlich. Wer DI konsequent einsetzt, kommt tatsächlich zu deutlich besser strukturiertem Quellcode. Der Weg dahin ist allerdings lang und beschwerlich. Und das nicht, weil DI eine komplizierte Technik ist. Das ist nicht der Fall. Der Grund ist, dass man ein Prinzip verstanden haben, muss, dass sich grundlegend auf den Programmaufbau auswirken kann (aber nicht unbedigt muss). Man muss ein wenig daran glauben.

Zum Glück gibt es auch ein wenig DI, genauso wie es auch ein wenig OOP damals gab. Auch wenn viele Puristen davon nicht viel halten, ich kann diesen Ansatz vertreten,dd aman damit in das Thema hineinwachsen kann.

Warum AutoFac? Gegenfrage: Warum nicht? Es gibt über ein Dutzend DI-Container, AutoFac ist einer der Namen, die immer wieder genannt werden. Die Webseite macht einen guten Eindruck, das Projekt wird laufend weiterentwickelt was sehr wichtig ist, es gibt viele Beispiele (u.a. im Rahmen von WCF), viele Fragen mit Antworten auf StackOverflow usw. für einen DI-Container muss man sich entscheiden (mir sagt Unity vom Pattern&Practices Team bei Microsoft nicht ganz so zu, was aber eher eine Frage der persönlichen Präferenzen ist und die sind bekanntlich breit gestreut). Und da in einem Projekt, mit dem ich beruflich zu tun hatte, AutoFac verwendet wurde, war dies der Anlass mich selber etwas mit AutoFac zu beschäftigen.

Die sehr gut gemachte Projektwebseite ist http://autofac.readthedocs.io/en/latest/index.html

Schritt 1: AutoFac hinzufügen

Das geht dank Package Manager-Konsole sehr einfach:

Install-Package AutoFac

Schritt 2: Typen registrieren

Ausgangspunkt ist ein sehr kleines Konsolenprogramm, das ein Interface und ein paar Klassen verwendet:

>IDocumentService.cs
>DocumentFileService.cs
>DocumentViewModel.cs
>MainViewModel.cs

Das Ziel soll es sein, eine Instanz der MainViewModel-Klasse zu erhalten, deren Documents-Eigenschaft eine Reihe von DocumentViewModel-Instanzen liefert, die zuvor per DocumentFileService, die IDocumentService mit ihrer GetDocuments-Methode implementiert, aus einer Xml-Datei eingelesen wurden.

Der Beitrag ist aktuell nur provisorisch, ich werde ihn in den nächsten Tagen noch einmal überarbeiten. Grundsätzlich hat es aber funktioniert:)