Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 5 Min.

Aus HTML mach PDF

So setzen Sie das NuGet-Package DinkToPdf ein.
© dotnetpro
Es existieren zahlreiche kommerzielle Bibliotheken für das Erstellen von PDF-Dateien in C#, wie zum Beispiel IronPDF [1] und Aspose.PDF [2]. Wer eine kostenfreie Bibliothek für die Erstellung von PDF-Dateien sucht, kann beispielsweise zwischen PDFsharp [3] und DinkToPdf [4] wählen.Mit PDFsharp werden die PDF-Dateien mit Zeichenroutinen, die aus GDI+ bekannt sind, erstellt. Fast alle Funktionen von GDI+ sind auch in PDFsharp verfügbar [5].Im Gegensatz dazu wandelt DinkToPdf HTML-Code in PDF-Dateien um, wobei auch CSS-Formatierungen möglich sind. Aufgrund der Vertrautheit vieler Webentwickler mit HTML wird die Entscheidung vermutlich zugunsten von DinkToPdf fallen.

Installation und Konfiguration von DinkToPdf

DinkToPdf, eine plattformübergreifende Bibliothek, fungiert als Wrapper für die wkhtmltopdf-Bibliothek. wkhtmltopdf ist ein Open-Source-Befehlszeilentool (LGPLv3), das HTML-Code unter Verwendung einer WebKit-Rendering-Engine in PDF umwandelt [6].DinkToPdf ist als NuGet-Package in der Version 1.08 verfügbar und kann über den NuGet-Paket-Manager oder mit dem Befehl Install-Package DinkToPdf über die Paket-Manager-Konsole installiert werden. Dabei werden die DLL-Dateien aus der wkhtmltopdf-Bibliothek nicht automatisch installiert; diese müssen manuell zum Projekt hinzugefügt werden.Wir installieren jedoch die benötigte DLL-Datei aus der wkhtmltopdf-Bibliothek zunächst nicht, damit wir die entsprechende Fehlermeldung generieren können, die auftritt, wenn die DLL-Datei fehlt.In unserem Beispiel verwenden wir eine MVC-Webseite, .NET 8 und C#. Zunächst installieren wir das NuGet-Pa­ckage DinkToPdf. Anschließend wird der Service in der Datei Program.cs wie folgt registriert:

<span class="hljs-keyword">var</span> converter = <span class="hljs-keyword">new</span><span class="hljs-type"></span> SynchronizedConverter(
  <span class="hljs-keyword">new</span><span class="hljs-type"></span> PdfTools());
builder.Services.AddSingleton&lt;IConverter&gt;(converter); 
Hiermit haben wir den HTML-zu-PDF-Converter aus dem NuGet-Package DinkToPdf als Service registriert und können diesen mittels Dependency Injection überall in unserem Projekt verwenden.

Konfiguration der PDF-Seite

DinkToPdf bietet drei Hauptklassen für die Konfiguration:
  • Die Klasse GlobalSettings besteht aus den allgemeinen Konfigurationseigenschaften für das PDF-Dokument. Wir verwenden nur einige dieser Eigenschaften, um den Farbmodus, die Ausrichtung, das Papierformat, den Dokumententitel der Seite einzurichten.
  • Die Klasse ObjectSettings besteht aus den Eigenschaften, die mit dem Inhalt des PDF-Dokuments zusammenhängen. Hier können wir zum einen die Paginierung und den Inhalt der Kopf- und Fußzeilen festlegen. Zum anderen gibt es noch die Web-Einstellungen und die HtmlContent-Eigenschaft. In den Web-Einstellungen der ObjectSettings lässt sich auch festlegen, ob JavaScript aktiviert sein soll oder nicht und ob eine – und welche – Style-Sheet-Datei für das Rendern des HTML-Codes verwendet werden soll. In unserem Beispiel ist das die Datei PDFstyles.css im Ordner wwwroot/css; diese formatiert die Tabelle mit einem blauen Header und einem blauen Rahmen (Listing 1). Die Html­Content-­Eigenschaft ist eine sehr wichtige Eigenschaft dieser Klasse; ihr wird später die von uns generierte HTML-Vorlage übergeben.
Listing 1: Inhalt der Datei PDFstyles.css
&lt;span class="hljs-selector-tag"&gt;h1&lt;/span&gt; {&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;color&lt;/span&gt;: blue;&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;text-align&lt;/span&gt;: center;&lt;br/&gt;}&lt;br/&gt;&lt;span class="hljs-selector-tag"&gt;table&lt;/span&gt; {&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;width&lt;/span&gt;: &lt;span class="hljs-number"&gt;100%&lt;/span&gt;;&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;border-collapse&lt;/span&gt;: collapse;&lt;br/&gt;}&lt;br/&gt;&lt;span class="hljs-selector-tag"&gt;table&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;th&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;td&lt;/span&gt; {&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;border&lt;/span&gt;: &lt;span class="hljs-number"&gt;1px&lt;/span&gt; solid blue;&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;font-size&lt;/span&gt;: &lt;span class="hljs-number"&gt;22px&lt;/span&gt;;&lt;br/&gt;}&lt;br/&gt;&lt;span class="hljs-selector-tag"&gt;td&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;th&lt;/span&gt; {&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;padding&lt;/span&gt;: &lt;span class="hljs-number"&gt;10px&lt;/span&gt;;&lt;br/&gt;}&lt;br/&gt;&lt;span class="hljs-selector-tag"&gt;th&lt;/span&gt; {&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;background-color&lt;/span&gt;: blue;&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;color&lt;/span&gt;: white;&lt;br/&gt;  &lt;span class="hljs-attribute"&gt;text-align&lt;/span&gt;: left;&lt;br/&gt;}  
  • Zuletzt gibt es noch die Klasse HtmlToPdfDocument, welche die GlobalSettings und ObjectSettings als Eigenschaften beinhaltet.
GlobalSettingsObjectSettingsUm sich die Arbeit zu vereinfachen und die Konfiguration der PDF-Datei immer wieder verwenden zu können, wird diese in eine separate Klasse ausgelagert, die uns das fertig konfigurierte Objekt HtmlToPdfDocument zurückgibt (siehe Listing 2). Später wird dann noch der HTML-Code an das Objekt HtmlToPdfDocument übergeben.
Listing 2: Die Eigenschaften unserer PDF-Datei werden in einer separaten Klasse gesetzt
public class PdfConfigSettings&lt;br/&gt;{&lt;br/&gt;  public static HtmlToPdfDocument &lt;br/&gt;      GetHtmlToPdfDocument()&lt;br/&gt;  {&lt;br/&gt;    var globalSettings = new GlobalSettings&lt;br/&gt;    {&lt;br/&gt;      ColorMode = ColorMode.Color,&lt;br/&gt;      Orientation = Orientation.Portrait,&lt;br/&gt;      PaperSize = PaperKind.A4,&lt;br/&gt;      Margins = new MarginSettings {Top = 10},&lt;br/&gt;      DocumentTitle = "",&lt;br/&gt;    };&lt;br/&gt;    var objectSettings = new ObjectSettings&lt;br/&gt;    {&lt;br/&gt;      PagesCount = true,&lt;br/&gt;      HtmlContent = "",  // hier wird später der &lt;br/&gt;                            HTML-Code eingefügt&lt;br/&gt;      WebSettings = { &lt;br/&gt;        DefaultEncoding = "utf-8", &lt;br/&gt;        EnableJavascript = false, &lt;br/&gt;        UserStyleSheet = Path.Combine(&lt;br/&gt;          Directory.GetCurrentDirectory(),&lt;br/&gt;          "wwwroot/css", "PDFstyles.css") &lt;br/&gt;      },&lt;br/&gt;      FooterSettings = { &lt;br/&gt;        FontName = "Calibri, Arial", &lt;br/&gt;        FontSize = 8, &lt;br/&gt;        Right = "Seite [page] von [toPage]", &lt;br/&gt;        Line = false }&lt;br/&gt;    };&lt;br/&gt;    var htmlToPdfDocument = new HtmlToPdfDocument()&lt;br/&gt;    {&lt;br/&gt;      GlobalSettings = globalSettings,&lt;br/&gt;      Objects = { objectSettings }&lt;br/&gt;    };&lt;br/&gt;    return htmlToPdfDocument;&lt;br/&gt;  }&lt;br/&gt;} 

Erstellung von Beispieldaten für das PDF-Dokument

In unserem Beispiel möchten wir Informationen über die Mitglieder eines fiktiven Vereins als PDF-Datei ausgeben und auf der Webseite anzeigen und dort auch zum Download anbieten. Dazu wurde zunächst eine Klasse Members und danach ­eine Klasse ­Data mit einer Methode Get­AllMembers() erstellt. Die Methode ­GetAllMembers() gibt eine Liste von 20 Mitgliedern zurück; diese Mitgliederdaten wurden mittels ChatGPT ­erstellt.

Generierung des HTML-Codes

Jetzt brauchen wir noch eine Methode, die uns eine Tabelle mit den Mitgliederdaten in HTML zurückgibt. Mittels einer Klasse PdfReportGenerator sowie der Methode GetHTML­String() lassen wir uns den HTML-Code für unsere Mitgliederliste erstellen (Listing 3).
Listing 3: Die Klasse PdfReportGenerator zum Erstellen des HTML-Codes
public static class PdfReportGenerator&lt;br/&gt;{&lt;br/&gt;  public static string GetHTMLString()&lt;br/&gt;  {&lt;br/&gt;    var members = Data.GetAllMembers();&lt;br/&gt;    var sb = new StringBuilder();&lt;br/&gt;    sb.Append(@"&lt;br/&gt;                &amp;lt;html&amp;gt;&lt;br/&gt;                  &amp;lt;head&amp;gt;&lt;br/&gt;                  &amp;lt;/head&amp;gt;&lt;br/&gt;                  &amp;lt;body&amp;gt;&lt;br/&gt;                    &amp;lt;div class='header'&amp;gt;&lt;br/&gt;                      &amp;lt;h1&amp;gt;Mitglieder-Liste&amp;lt;/h1&amp;gt;&amp;lt;/div&amp;gt;&lt;br/&gt;                    &amp;lt;table align='center'&amp;gt;&lt;br/&gt;                      &amp;lt;tr&amp;gt;&lt;br/&gt;                        &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;&lt;br/&gt;                        &amp;lt;th&amp;gt;Vorname&amp;lt;/th&amp;gt;&lt;br/&gt;                        &amp;lt;th&amp;gt;Strasse&amp;lt;/th&amp;gt;&lt;br/&gt;                        &amp;lt;th&amp;gt;PLZ&amp;lt;/th&amp;gt;&lt;br/&gt;                        &amp;lt;th&amp;gt;Ort&amp;lt;/th&amp;gt;&lt;br/&gt;                      &amp;lt;/tr&amp;gt;");&lt;br/&gt;    foreach (var member in members)&lt;br/&gt;    {&lt;br/&gt;      sb.AppendFormat(@"&amp;lt;tr&amp;gt;&lt;br/&gt;                          &amp;lt;td&amp;gt;{0}&amp;lt;/td&amp;gt;&lt;br/&gt;                          &amp;lt;td&amp;gt;{1}&amp;lt;/td&amp;gt;&lt;br/&gt;                          &amp;lt;td&amp;gt;{2}&amp;lt;/td&amp;gt;&lt;br/&gt;                          &amp;lt;td&amp;gt;{3}&amp;lt;/td&amp;gt;&lt;br/&gt;                          &amp;lt;td&amp;gt;{4}&amp;lt;/td&amp;gt;&lt;br/&gt;                        &amp;lt;/tr&amp;gt;", &lt;br/&gt;                        member.Firstname, member.&lt;br/&gt;                          LastName, member.Street, &lt;br/&gt;                        member.PLZ, member.City);&lt;br/&gt;    }&lt;br/&gt;    sb.Append(@"&lt;br/&gt;                    &amp;lt;/table&amp;gt;&lt;br/&gt;              &amp;lt;/body&amp;gt;&lt;br/&gt;       &amp;lt;/html&amp;gt;");&lt;br/&gt;    return sb.ToString();&lt;br/&gt;  }&lt;br/&gt;} 
In unserem Controller können wir in der Methode Show­PDF() nun mit vier Codezeilen die PDF-Datei ausgeben, siehe Listing 4. Zunächst lassen wir uns mit der Methode Get­HtmlTo­PdfDocument() aus der Klasse PdfConfigSettings ein bereits konfiguriertes Objekt der Klasse HtmlToPdfDocument zurückgeben. Anschließend übergeben wir an die Eigenschaft ­HtmlContent den HTML-Code, den wir uns mit Get­HTMLString() aus der Klasse PdfReportGenerator zurück­geben lassen.
Listing 4: Die PDF-Datei im Controller ausgeben
using CreatePDFOnWeb.PDFHelper;&lt;br/&gt;using DinkToPdf;&lt;br/&gt;using DinkToPdf.Contracts;&lt;br/&gt;using Microsoft.AspNetCore.Mvc;&lt;br/&gt;namespace CreatePDFOnWeb.Controllers&lt;br/&gt;{&lt;br/&gt;  public class PdfController : Controller&lt;br/&gt;  {&lt;br/&gt;    private readonly IConverter _converter; &lt;br/&gt;    public PdfController(IConverter converter)&lt;br/&gt;    {&lt;br/&gt;      _converter = converter;&lt;br/&gt;    }&lt;br/&gt;    public IActionResult ShowPDF()&lt;br/&gt;    {&lt;br/&gt;      HtmlToPdfDocument htmlToPdfDocument = &lt;br/&gt;        PdfConfigSettings.GetHtmlToPdfDocument();&lt;br/&gt;      htmlToPdfDocument.Objects[0].HtmlContent = &lt;br/&gt;        PdfReportGenerator.GetHTMLString();&lt;br/&gt;      byte[] file = _converter.Convert(&lt;br/&gt;        htmlToPdfDocument);&lt;br/&gt;      return File(file, "application/pdf");&lt;br/&gt;    }&lt;br/&gt;  }&lt;br/&gt;} 

Ausgabe der PDF-Datei – schlägt fehl

Nun übergeben wir das HtmlToPdfDocument-Objekt an den Converter-Service, den wir per Dependency Injection in den Kontroller eingebunden haben. Als Ergebnis erhalten wir ein Byte-Array. Jetzt müssen wir nur noch das Byte-Array als File mit dem ContentTypeapplication/pdf zurückgeben, und die PDF-Datei sollte im Browser angezeigt werden.

Externe DLL-Datei hinzufügen und registrieren

Mit dem bisherigen Code funktioniert das jedoch noch nicht. Die Anwendung lässt sich kompilieren und starten, doch erhalten wir beim Versuch, die PDF-Seite auszugeben, einen Laufzeitfehler (siehe Bild 1). Die Fehlermeldung „Unable to load DLL 'libwkhtmltox' or one of its dependencies:“ weist auf eine fehlende DLL-Datei namens libwkhtmltox hin.
Fehlermeldung wegen fehlender DLL-Datei (Bild 1) © Autor
Die benötigte DLL-Datei lässt sich aus dem DinkToPdf-­Repository bei GitHub [4] herunterladen und im Projekt platzieren; libwkhtmltox.dll findet sich im Ordner \v0.12.4\64 bit. Wir kopieren sie in unserem Beispiel in den Ordner wwwroot\pdfCreatorDll. Damit unsere Anwendung diese DLL-Datei finden und verwenden kann, müssen wir sie zunächst registrieren.Dazu haben wir eine Klasse CustomAssemblyLoadContext
.cs
angelegt (Listing 5). Diese erbt von der Klasse AssemblyLoadContext und überschreibt die Methoden LoadUnma­nagedLibrary und LoadUnmanagedDll.
Listing 5: Inhalt der Klasse CustomAssemblyLoadContext
public class CustomAssemblyLoadContext : &lt;br/&gt;    AssemblyLoadContext&lt;br/&gt;{&lt;br/&gt;  public nint LoadUnmanagedLibrary(&lt;br/&gt;    string absolutePath)&lt;br/&gt;  {&lt;br/&gt;    return LoadUnmanagedDll(absolutePath);&lt;br/&gt;  }&lt;br/&gt;  protected override nint LoadUnmanagedDll(&lt;br/&gt;    string unmanagedDllName)&lt;br/&gt;  {&lt;br/&gt;    return LoadUnmanagedDllFromPath(unmanagedDllName);&lt;br/&gt;  }&lt;br/&gt;} 
Zuletzt müssen wir noch das Laden der DLL-Datei in der Datei Program.cs initiieren (Listing 6).
Listing 6: Die benötigten Einträge in der Datei Program.cs
// register libwkhtmltox.dll &lt;br/&gt;var contentRootPath = &lt;br/&gt;  builder.Environment.ContentRootPath;&lt;br/&gt;var libwkhtmltoxPath = Path.Combine(contentRootPath, &lt;br/&gt;  $"wwwroot\\pdfCreatorDll\\libwkhtmltox.dll");&lt;br/&gt;var assemblyLoadContext = &lt;br/&gt;  new CustomAssemblyLoadContext();&lt;br/&gt;assemblyLoadContext.LoadUnmanagedLibrary(&lt;br/&gt;  libwkhtmltoxPath);&lt;br/&gt;// register service DinkToPdf&lt;br/&gt;var converter = new SynchronizedConverter(&lt;br/&gt;  new PdfTools());&lt;br/&gt;builder.Services.AddSingleton&amp;lt;IConverter&amp;gt;(converter); 

PDF-Datei im Webbrowser erstellen

Nach Abschluss dieser Schritte ist die PDF-Erstellung in der Webanwendung realisierbar (siehe Bild 2).
Ansicht der PDF-Datei im Browser (Bild 2) © Autor
Das Codebeispiel dieses Artikels kann unter [7] he­runtergeladen werden.

Fussnoten

  1. IronPDF, The C# PDF Library, http://www.dotnetpro.de/SL2407DinkToPdf1
  2. Aspose.PDF for .NET Documentation, http://www.dotnetpro.de/SL2407DinkToPdf2
  3. PDFsharp, http://www.dotnetpro.de/SL2407DinkToPdf3
  4. DinkToPdf auf GitHub, http://www.dotnetpro.de/SL2407DinkToPdf4
  5. PDFsharp & MigraDoc, Overview, http://www.dotnetpro.de/SL2407DinkToPdf5
  6. wkhtmltopdf, http://www.dotnetpro.de/SL2407DinkToPdf6
  7. ChristianKiefer / CreatePDFOnWebsites auf GitHub, http://www.dotnetpro.de/SL2407DinkToPdf7

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige