Przewodnik PDFsharp: Tworzenie plików PDF za pomocą MigraDoc i PdfSharpCore
PDFsharp to biblioteka .NET o otwartym kodzie źródłowym do tworzenia i edycji dokumentów PDF z poziomu kodu C#. Wystarczy narysować tekst, linie i obrazy na stronie, wybrać opcję „Zapisz” i gotowe – plik PDF. Bez silnika przeglądarki ani natywnego pliku binarnego. Projekt powstał w 2005 roku i wiele faktur, raportów i certyfikatów generowanych z zaplecza .NET nadal przez niego przechodzi.
Napisałem to dla deweloperów, którzy potrzebują plików PDF na serwerze i chcą wiedzieć, na co się decydują. Omówimy, jak PDFsharp i MigraDoc współpracują ze sobą, którą kompilację zainstalować, pierwszy plik roboczy, problem z czcionkami w systemie Linux, ostatnią zmianę licencji i moment, w którym warto wybrać coś innego.
Czym jest PDFsharp i co potrafi?
Za biblioteką PDFsharp kryje się empira Software GmbH, mała niemiecka firma, która utrzymuje tę technologię przy życiu od blisko dwudziestu lat. Większość czasu poświęcasz na zajęcia w XGraphics. Jeśli kiedykolwiek malowałeś w WinForms z System.Drawing.Graphics, poczujesz się jak w domu w ciągu dziesięciu minut: czcionka, pędzel, X i Y, start.
W zestawie otrzymujesz:
- Twórz dokumenty PDF od podstaw, używając tekstu, kształtów wektorowych, linii i obrazów
- Otwieraj istniejące pliki PDF i dodawaj do ich stron zawartość, np. pieczątki, znaki wodne lub numery stron
- Łącz i dziel dokumenty, importując strony z jednego pliku do drugiego
- Osadzaj i twórz podzbiory czcionek , aby plik wyglądał tak samo na każdym komputerze
- Dodaj zakładki, linki i metadane dokumentu, takie jak tytuł, autor i słowa kluczowe
- Chroń pliki hasłami i flagami uprawnień
- Podpisuj dokumenty cyfrowo (od wersji 6.2)
Wdrożenie jest nudne, co mam na myśli jako pochwałę. Wszystko odbywa się w kodzie zarządzanym, więc osoba zarządzająca nie musi instalować Chrome'a bez interfejsu graficznego ani szukać biblioteki DLL Ghostscript o 2 w nocy. Odwołujesz się do jednego pakietu NuGet, wysyłasz i gotowe.
A teraz haczyk. Dostajesz płótno i nic więcej. Długi akapit sięga dolnego marginesu? Twój problem. Tabela wykracza poza pierwszą stronę? Też Twój, chyba że włączysz MigraDoc.
PDFsharp i MigraDoc: Która warstwa jest Ci potrzebna?
Ten sam dostawca, ten sam harmonogram wydań, zupełnie inne zadania. Fundacja MigraDoc mieści się piętro wyżej od PDFsharp. Zamiast mówić jej, gdzie ma trafić ciąg, podajesz jej sekcje, akapity, tabele, nagłówki, stopki, style i okazjonalne wykresy, a ona sama ustala, gdzie wszystko trafi. Wychodzi plik PDF. Albo RTF, dla kolegi, który upiera się przy otwieraniu wszystkiego w Wordzie.
Mój skrót: PDFsharp to „umieść ten tekst w punkcie x=40, y=120”. MigraDoc to „oto trzydzieści wierszy i nagłówek, który się powtarza, sortujesz strony”.
| Zadanie | Najlepiej pasuje | Dlaczego |
|---|---|---|
| Jednostronicowy certyfikat lub bilet z ustalonymi pozycjami | PDFsharp | Pełna kontrola nad każdą współrzędną |
| Raport wielostronicowy z tabelami i nagłówkami bieżącymi | MigraDoc | Automatyczna paginacja i style |
| Faktura ze zmienną liczbą pozycji | MigraDoc | Tabele rosną i dzielą się na strony |
| Pieczątka, znak wodny lub numeracja stron w istniejącym pliku PDF | PDFsharp | MigraDoc tworzy tylko nowe dokumenty |
| Scalanie lub dzielenie istniejących plików | PDFsharp | Importowanie stron to funkcja PDFsharp |
| Wykres biznesowy w raporcie | MigraDoc | Wbudowana obsługa wykresów |
| Mieszane: wygenerowany raport i okładka zaprojektowana na zamówienie | Obydwa | MigraDoc może renderować na stronie PDFsharp |
Prawdziwe projekty zazwyczaj kończą się na jednym i drugim. Tekst główny w MigraDoc, ręcznie narysowana okładka lub pieczątka na pliku PDF od jakiegoś dostawcy w dolnej warstwie. Tak czy inaczej, nie da się uniknąć instalacji PDFsharp, ponieważ pakiet MigraDoc przeciąga go jako zależność.
Wyjaśnienie kompilacji PDFsharp: kompilacja podstawowa, GDI+ i WPF
Nowi użytkownicy zazwyczaj trafiają na następną pozycję na liście pakietów w NuGet. PDFsharp 6 jest dostępny w trzech kompilacjach, każda z własnym odpowiednikiem MigraDoc.
| Pakiet NuGet | Zbudować | Platformy | Czcionki i obrazy |
|---|---|---|---|
| PDFsharp / PDFsharp-MigraDoc | Rdzeń | Windows, Linux, macOS | Potrzebny jest program do rozpoznawania czcionek; obrazy BMP, PNG, JPEG |
| PDFsharp-GDI / PDFsharp-MigraDoc-GDI | GDI+ | Tylko Windows | Używa zainstalowanych czcionek za pośrednictwem System.Drawing |
| PDFsharp-WPF / PDFsharp-MigraDoc-WPF | WPF | Tylko Windows | Używa zainstalowanych czcionek za pośrednictwem WPF |
Aktualne pakiety są przeznaczone dla platform .NET 8, 9 i 10, a także .NET Standard 2.0 i .NET Framework 4.6.2. Obejmuje to praktycznie wszystko, nad czym wciąż trwają prace, od zakurzonego narzędzia WinForms po zupełnie nowe API ASP.NET Core.
Aplikacja konsolowa, API webowe, Docker, Azure Functions, cokolwiek na Linuksa? Wersja Core. GDI+ lub WPF mają sens tylko w przypadku aplikacji desktopowej Windows, w której potrzebne są czcionki systemowe lub podgląd w natywnej kontrolce. Ktoś na Stack Overflow kiedyś zapytał, czy jego aplikacja konsolowa potrzebuje wersji WPF. Nie.

Jak zainstalować PDFsharp z NuGet w programie Visual Studio
Nadal znajdziesz posty na forach z czasów WinForms, które radzą Ci, żebyś ściągnął ZIP, wyciągnął DLL i sam dodał odnośnik. Zignoruj je. Zainstaluj PDFsharp przez NuGet; menedżer pakietów śledzi wersje, więc Ty nie musisz.
- Otwórz swoje rozwiązanie w programie Visual Studio i kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań.
- Wybierz opcję Zarządzaj pakietami NuGet , przejdź do karty Przeglądaj i wyszukaj „PDFsharp”.
- Wybierz PDFsharp (kompilacja podstawowa) lub PDFsharp-MigraDoc, jeśli potrzebujesz również układu dokumentu. Sprawdź, czy wydawcą jest Empira Software GmbH.
- Kliknij Zainstaluj i zaakceptuj monit o licencję.
- Skompiluj projekt raz, aby mieć pewność, że pakiet został poprawnie przywrócony.
Użytkownicy terminali mogą pominąć klikanie:
bash dotnet dodaj pakiet PDFsharp dotnet dodaj pakiet PDFsharp-MigraDoc
W konsoli Menedżera pakietów znajduje się ta sama opcja: Install-Package PDFsharp. I proszę nie mieszać kompilacji. Widziałem, jak zespół stracił całe popołudnie z powodu konfliktów typów, ponieważ jeden projekt odwoływał się do PDFsharp, a sąsiedni pobrał PDFsharp-GDI.
Twój pierwszy dokument PDF z PDFsharp w C
Poniżej znajduje się przykład najmniejszego programu generującego jednostronicowy plik PDF. Działa on w systemie Core na dowolnym systemie operacyjnym, o ile skonfigurowany jest moduł rozpoznawania czcionek (następna sekcja).
```wyrazisty
używając PdfSharp.Drawing;
używając PdfSharp.Pdf;
// PDFsharp 6.5+ wymaga wybrania licencji przed pierwszym użyciem
PdfSharpLicense.SetAgplLicense();
var document = nowy PdfDocument();
document.Info.Title = "Witaj PDFsharp";
Strona PdfPage = document.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(strona);
var font = new XFont("Arial", 20, XFontStyleEx.Bold);
gfx.DrawString("Witaj, PDFsharp!", czcionka, XBrushes.Black,
nowy XRect(0, 0, strona.Szerokość.Punkt, strona.Wysokość.Punkt),
XStringFormats.Center);
dokument.Zapisz("cześć.pdf");
```
Każdy program PDFsharp ma ten schemat: dokument, strona, XGraphics, rysowanie, zapisywanie. Jednostki to punkty (1/72 cala), a początek układu współrzędnych znajduje się w lewym górnym rogu. W wersji 6.2.x należy usunąć wiersz licencji. To API pojawiło się dopiero w wersji 6.5.0.
A wersja MigraDoc:
```wyrazisty
używając MigraDoc.DocumentObjectModel;
używając MigraDoc.Rendering;
var doc = nowy Dokument();
Sekcja sekcja = doc.AddSection();
section.AddParagraph("Witaj, MigraDoc!");
var renderer = nowy moduł renderowania dokumentów Pdf { Document = doc };
renderer.RenderDocument();
renderer.PdfDocument.Save("witaj-migradoc.pdf");
```
Żadnych współrzędnych. Rzuć 500 akapitów, a otrzymasz tyle stron, ile potrzeba, bez żadnego kodu paginacji po swojej stronie.
Czcionki w kompilacji PDFsharp Core: problem z programem Resolver
Zapytaj dookoła, a czcionki to najczęstszy problem, jaki usłyszysz. Kompilacje GDI+ i WPF odczytują zainstalowane czcionki TrueType z systemu Windows. Kompilacja Core nie może niczego zakładać, ponieważ kontener Slim Linux często nie zawiera żadnych użytecznych czcionek. Dlatego pierwsze wdrożenie Dockera zazwyczaj kończy się wyjątkiem informującym o braku odpowiedniej czcionki.
Rozwiązaniem jest resolver czcionek, klasa implementująca IFontResolver. Ma ona dwie metody:
- ResolveTypeface mapuje żądaną rodzinę i styl (np. „Arial”, pogrubienie) na nazwę czcionki
- GetFont zwraca surowe bajty pliku TTF dla tej nazwy twarzy
Zarejestruj go raz podczas uruchamiania za pomocą GlobalFontSettings.FontResolver, przed utworzeniem pierwszego XFont.
```wyrazisty
klasa publiczna AppFontResolver : IFontResolver
{
public FontResolverInfo? ResolveTypeface(string family, bool bold, bool italic)
=> new FontResolverInfo(bold ? "Inter-Bold" : "Inter-Regular");
public byte[]? GetFont(string faceName) => File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, "Fonts", faceName + ".ttf"));
}
GlobalFontSettings.FontResolver = nowa aplikacjaFontResolver();
```
Rzeczy, które warto wiedzieć, zanim sam to zrobisz:
- Przechowuj pliki TTF w folderze Fonts w projekcie i ustaw ich kopiowanie do katalogu wyjściowego lub osadź je jako zasoby, aby obraz kontenera zawsze je zawierał.
- Wersja 6.2.0 usunęła starą wersję CoreBuildFontResolver. W systemie Windows lub WSL2 można przywrócić podobne zachowanie za pomocą GlobalFontSettings.UseWindowsFontsUnderWindows, ale nie działa to w systemach Linux i macOS.
- Oficjalne repozytorium próbek zawiera plik SubstitutingFontResolver, który możesz skopiować jako punkt wyjścia.
- Sprawdź licencję czcionki przed osadzeniem komercyjnego kroju pisma w generowanych plikach. Otwarte czcionki, takie jak Inter, Roboto czy Noto, całkowicie omijają ten problem.
Po zainstalowaniu resolvera dane wyjściowe wyglądają identycznie w systemach Windows, Linux i macOS.
Łączenie, podpisywanie i zabezpieczanie plików za pomocą PDFsharp 6
Wiele zespołów nigdy nie tworzy dokumentu od podstaw. Używają biblioteki do sklejania, stemplowania lub blokowania już istniejących plików. Scalenie to kilka linijek tekstu: otwórz każdy plik źródłowy w trybie importu i skopiuj strony.
csharp var output = new PdfDocument(); foreach (var path in new[] { "part1.pdf", "part2.pdf" }) { using var input = PdfReader.Open(path, PdfDocumentOpenMode.Import); foreach (PdfPage p in input.Pages) output.AddPage(p); } output.Save("merged.pdf");
Podział to ta sama pętla wstecz, jeden plik wyjściowy na stronę lub zakres. W celach bezpieczeństwa document.SecuritySettings przyjmuje hasło użytkownika, hasło właściciela oraz flagi uprawnień (drukowanie, kopiowanie tekstu itd.).
Dwie długo wyczekiwane funkcje w końcu pojawiły się w wersji 6.2:
- Podpisy cyfrowe oparte na CMS. Domyślny podpis jest dostarczany w osobnym pakiecie PDFsharp.Cryptography, a można go podłączyć, implementując IDigitalSigner. Obsługa serwera znaczników czasu działa w nowoczesnej platformie .NET, ale nie w kompilacji .NET Framework.
- Wyjście PDF/A do archiwizacji. Oficjalna dokumentacja opisuje je jako działające „z pewnymi ograniczeniami” i wciąż w fazie rozwoju, dlatego przed użyciem w celu sprawdzenia zgodności należy zweryfikować wynik za pomocą programu do sprawdzania plików PDF/A.
W tej wersji wprowadzono także kolorowe glify emoji i zarządzaną implementację MD5, co ma znaczenie niezależnie od tego, czy używasz reguł FIPS, czy Blazor.
Repozytorium PDFsharp, rozwidlenia PdfSharpCore i wersje 1.x
Wyszukaj w GitHubie hasło PDFsharp, a znajdziesz kilka projektów o niemal identycznej nazwie. Zrzuć winę na historię.
Stara wersja 1.x (1.50, 1.51) działała tylko w środowisku .NET Framework. Kiedy pojawił się .NET Core, użytkownicy nie chcieli czekać, więc przenieśli go sami. PdfSharpCore, zapoczątkowany przez Stefana Steigera, a później podchwycony przez inne forki, jest tym, który zna większość osób. Usunął on GDI+ i uruchomił kod w systemie Linux na lata przed oficjalną premierą.
Potem pojawił się PDFsharp 6: porządna przeróbka na nowoczesnej platformie .NET z oficjalną wieloplatformową kompilacją Core. Forki straciły większość racji bytu.
| Projekt | Konserwator | Platformy | Status |
|---|---|---|---|
| PDFsharp 6.x (repozytorium empira/PDFsharp) | Empira Software GmbH | .NET 8–10, .NET Standard 2.0, .NET Framework 4.6.2 | Aktywnie utrzymywane |
| PDFsharp 1.5x | Empira Software GmbH | Tylko .NET Framework | Kod źródłowy jest przechowywany na GitHubie, nie jest już utrzymywany |
| PdfSharpCore i jego forki | Wspólnota | .NET Core / .NET Standard 2.0 | Różni się w zależności od forka, wolniejsze aktualizacje |
| PDFsharp-MigraDoc 6.x | Empira Software GmbH | Tak samo jak PDFsharp 6 | Aktywnie utrzymywane |
A więc wątek „PdfSharp kontra PdfSharpCore”, który ciągle pojawia się na Reddicie? Nowy projekt, oficjalne pakiety. Zachowaj forka tylko wtedy, gdy stary kod już go wykorzystuje, a migracja nie jest teraz warta zachodu. A gdy dokumentacja okaże się uboga, skorzystaj z oddzielnego repozytorium przykładów Empiry. Jego foldery i pliki to gotowe do uruchomienia przykłady, co jest lepsze od zgadywania.
Czy PDFsharp jest darmowy? Zmiany w licencjonowaniu w PDFsharp 6.5
Przez większość swojego istnienia, tak. Był na licencji MIT, co oznacza możliwość komercyjnego użytkowania praktycznie bez żadnych zobowiązań. Każda wersja, aż do 6.2.4 włącznie, nadal jest na licencji.
Wersja 6.5.0 to zmieniła. Biblioteka jest teraz objęta podwójną licencją:
- AGPL (bezpłatna). Aby ją włączyć, należy wywołać metodę PdfSharpLicense.SetAgplLicense() przed użyciem biblioteki. Licencja AGPL wymaga udostępnienia kodu źródłowego użytkownikom, w tym użytkownikom korzystającym z oprogramowania przez sieć, dlatego nie jest ona odpowiednia dla oprogramowania SaaS o zamkniętym kodzie źródłowym.
- Licencja komercyjna. Kupujesz klucz licencyjny od sprzedawcy i ładujesz go za pomocą PdfSharpLicense.LoadLicense(...). To zwalnia z obowiązku AGPL.
Od wersji 6.5.0 kod musi jawnie wybrać jeden z nich. Wersje zapoznawcze wersji 7.0 działają w ten sam sposób.
W rzeczywistości:
- Projekty Open Source zgodne z AGPL mogą nadal korzystać z najnowszej wersji za darmo.
- Produkty o zamkniętym kodzie źródłowym mogą albo kupić licencję komercyjną, albo pozostać przy wersji 6.2.x, która pozostaje na licencji MIT. Pozostanie na obecnym poziomie oznacza utratę przyszłych poprawek, więc rozważ ten koszt uczciwie.
- Cokolwiek wybierzesz, przeczytaj tekst licencji i poproś o podpis swojego zespołu prawnego. Niniejszy poradnik nie stanowi porady prawnej.

Gdzie PDFsharp zawodzi i z czym go łączyć
Biblioteka dobrze spełnia swoją rolę. Jej rola jest jednak ograniczona, a te same luki pojawiają się w każdym wątku na forum.
- Brak konwersji HTML do PDF. PDFsharp nie renderuje HTML ani CSS. Istnieje dodatek społecznościowy HtmlRenderer.PdfSharp, który obsługuje tylko HTML 4.01 i CSS poziomu 2, więc nowoczesne układy z flexboxem lub siatką nie będą działać. Zespoły potrzebujące szablonów HTML zazwyczaj sięgają po renderer bez przeglądarki.
- Brak JavaScript. Wykresów i treści tworzonych po stronie klienta nie można przechwytywać.
- Brak renderowania obrazów. PDFsharp nie może przekształcić strony PDF w PNG w celu wyświetlenia miniatur lub podglądu. Do tego potrzebny jest osobny rasteryzator.
- Ograniczona ekstrakcja tekstu. Można przeglądać strumień treści, ale nie ma API wysokiego poziomu, które zwracałoby czysty tekst z pozycjami. PdfPig, osobna biblioteka open source, została stworzona specjalnie do odczytu i ekstrakcji tekstu.
- Częściowa obsługa formularzy. Proste wypełnianie formularzy AcroForm działa; złożone formularze ze skryptami to zupełnie inna historia.
- Tabele wymagają MigraDoc. Dzięki prostemu PDFsharp możesz samodzielnie obliczyć wysokość każdego wiersza.
To wcale nie znaczy, że to zły wybór. Dokumenty oparte na danych, takie jak faktury, wyciągi, etykiety i certyfikaty, są dla niego idealne, a jego rozmiar jest minimalny. Pikselowo idealne kopie stron internetowych już nie.
PDFsharp dla faktur i potwierdzeń płatności za kryptowaluty
Paragony to prawdopodobnie najczęstszy element tworzony przez użytkowników PDFsharp. Paragony kryptograficzne są nieco bardziej wymagające niż te na karty. Dobra wiadomość: gdy bramka połączy się z Twoim webhookiem (wywołaniem zwrotnym HTTP wysyłanym po zmianie statusu płatności), masz wszystkie dane. Nie musisz niczego więcej szukać.
Co bym na siebie włożył:
- Numer zamówienia lub faktury oraz dane sprzedawcy
- Kwota w kryptowalucie i jej równowartość w walucie fiducjarnej w momencie płatności
- Moneta i sieć (na przykład USDT na TRON kontra USDT na Ethereum)
- Hash transakcji, dzięki któremu klient może go zweryfikować w eksploratorze bloków
- Skrócony adres portfela odbiorczego i czas potwierdzenia
- Kod QR łączący ze stroną transakcji lub faktury
Stała przestrzeń dla haszy i adresów. Klienci mrużą oczy, patrząc na nie pojedynczo, a w Arialu zero i wielkie O wyglądają jak bliźniaki. Jeśli hasz jest za szeroki, zawiń go; tekst o rozmiarze 6 punktów nikomu nie pomoże. Osadź czcionki, zapisz plik z zamówieniem i podpisz go, jeśli księgowy kiedykolwiek poprosi o paragon.
Nic z tego nie obejmuje faktycznego pobrania pieniędzy. W tym celu należy podłączyć bramkę taką jak Plisio . Przyjmuje ona BTC, USDT i wiele innych monet, wystawia fakturę i wywołuje Twój punkt końcowy za każdym razem, gdy zmienia się status. Twój program obsługi przekazuje dane do MigraDoc, a kupujący otrzymuje paragon z Twoim logo, gdy jest jeszcze na stronie z podziękowaniami.
Wniosek
Wracam do PDFsharp z jednego powodu: jest mały i nie przeszkadza. Wersja Core działa wszędzie tam, gdzie działa .NET, a MigraDoc przejmuje pracę nad układem, gdy kanwa nie wystarcza. Trzy rzeczy do ustalenia na początku: którą wersję, jak wczytywane są czcionki i z jakiej licencji korzystasz teraz, gdy wersja 6.5 przeszła na AGPL. Drukuj dane, a nie strony internetowe, a będzie działać latami.