Potrzeba generowania plików PDF pojawia się w każdej aplikacji, która umożliwia tworzenie raportów, zamówień czy faktur. Szperając po sieci znajdziemy dość duży wachlarz dostępnych rozwiązań, lecz większość z nich jest płatna. Jeżeli nie mamy możliwości skorzystania z takich bibliotek musimy szukać alternatywy wśród projektów open source. Jakiś czas temu sam miałem podobny problem. Poszukiwałem rozwiązania, które umożliwiłoby mi tworzenie plików PDF, najlepiej w jak najprostszy i najszybszy sposób. Ponieważ zajmuję się tworzeniem aplikacji internetowych dodatkowo zwracałem uwagę na możliwość tworzenia treści takich plików w oparciu o HTML, CSS i JS. Moje oczekiwania spełniły rozwiązania oparte o wkhtmltopdf

Wspomniane narzędzie pozwala generować pliki PDF z poziomu linii komend. Wystarczy wskazać stronę www (wskazanie ścieżki do pliku lub adres URL), którą chcemy zamienić na PDF, określić dodatkowe parametry (np lokalizację zapisu) i gotowe:

Dodatkowe parametry, o których wspomniałem można znaleźć w dokumentacji. Są nimi m.in:

  • -B, --margin-bottom – margines dolny
  • -L, --margin-left – margines lewy (wartość początkowa 10mm)
  • -R, --margin-right – margines prawy (wartość początkowa 10mm)
  • -T, --margin-top – margines górny
  • -O, --orientation – orientacja strony (Landscape lub Portrait)
  • -s, --page-size – ustawienie rozmiaru dokumentu : np A4, Letter (wartość początkowa – A4)
  • --javascript-delay – czas, który umożliwia wykonanie się wszystkich skryptów js (wartość początkowa 200 ms)

Przy pracy z wkhtmltopdf nie obyło się oczywiście bez nerwów i irytacji. Poniżej przedstawiam kilka problematycznych sytuacji jakie napotkałem i rozwiązań, które umożliwiły mi eliminację błędów.

1. “Dziwne, u mnie działa…”

Ta sama implementacja, te same pliki, ta sama wersja wkhtmltopdf. Dwa różne komputery/środowiska. U mnie pdf wygląda OK, ale po wgraniu na środowisko testowe czcionka została powiększona a jednostronicowy dokument nagle zajmuje dwie strony A4.

Czary? Jak zawsze nic nie dzieje się bez przyczyny. Wczytany HTML jest renderowany poprzez silnik WebKit w wirtualnym oknie przeglądarki. Rozmiar takiego okna zależny jest od rozdzielczości maszyny na której wywołujemy proces konwersji HTML do PDF. Jeżeli lokalnie będzie ona wynosić np 1600×1050, a na serwerze produkcyjnym 640×480, to pdf u klienta może zostać mocno powiększony.

Rozwiązanie:

  • Za pomocą CSS ustawiamy stałą szerokość dokumentu HTML oraz
  • używamy parametru --disable-smart-shrinking – wyłączamy strategię silnika WebKit zmieniającego wartości PPI/DPI

2. “Dziwne, czcionka jest inna…”

Znów ta sama implementacja, te same pliki. Dwa różne komputery/środowiska. Wydruk ma już poprawny rozmiar, ale na produkcji zawsze ustawia się na Times New Roman.

Przyczyną takiego błędu jest brak zainstalowanej czcionki na środowisku, gdzie występuje problem. Rozwiązanie jest banalne – instalacja brakujących plików czcionek. Osobiście używam Google Fonts w tego typu dokumentach, więc nie mam takich problemów. Jednak zdaje sobie sprawę, że dla niektórych minusem takiego rozwiązania będzie konieczność połączenia z internetem podczas generowania pdf.

3. “Tabelki są ucinane w losowych miejscach…”

Elementy zamówienia mają zostać przedstawione w formie tabelarycznej. Przy generowaniu wydruku wielostronicowego wiersze ucinane są w losowych miejscach.

Rozwiązanie:

  • Zastosowanie CSS:

  • Użycie javascript – skryptu Floriana Stancu, który łamie tabele w dokumencie HTML.

4. “Na produkcji style widoku HTML są nie poprawne…”

Po wgraniu aplikacji na środowisko produkcyjne nie widać wpływu CSS na widok. Arkusz stylów nie jest wczytywany podczas renderowania HTML przy konwersji do PDF.

W takiej sytuacji polecam sprawdzić ustawienia proxy. Wkhtmltopdf umożliwia wskazanie konkretnych wartości przy użyciu parametru --proxy.

5. “Strona pdf o niestandardowych rozmiarach i z uzupełnionym nagłówkiem, stopką i stronicowaniem”

Klient chce posiadać zapis etykiet do pdf. Etykieta ma niestandardowy rozmiar 10cm x 11cm. Ponadto wymagane jest numerowanie stron oraz dodanie nazwy produktu w nagłówku oraz adresu WWW w stopce strony.

Rozwiązanie:

  • Aby zaimplemenetować rozwiązanie musimy zajrzeć do dokumentacji, aby wybrać odpowiednie parametry :
    • Rozmiar dokumentu określimy przy użyciu : --page-width oraz --page-height
    • Treść nagłówka możemy określić przy użyciu: --header-left, --header-center, --header-right
    • Treść stopki możemy określić przy użyciu: --footer-left, --footer-center, --footer-right
    • Do numerowania stron możemy wykorzystać znaczniki [page]/[topage]

    Finalnie nasze polecenie będzie miało postać:


Powyżej przedstawiłem sposób generowania pdf bezpośrednio z poziomu linii komend. Jeżeli w swoich projektach wykorzystujecie ASP.NET MVC (tak jak ja) możecie użyć ułatwiającego implementację wrappera – np Rotativy. Jest to dość proste. Wystarczy zaciągnąć odpowiednią paczkę z NuGet`a .

Implementacja podglądu/zapisu pdf z użyciem Rotativy z poziomu kontrolera zbytnio nie różni się od wywoływania zwykłych widoków. Do metody zwracającej dokument podajemy model i określamy ewentualne parametry konwersji :

Dodawanie parametrów konwersji odbywa się z użyciem właściwości CustomSwitches :

Powyższe implementacje będą skutkowały otworzeniem pdf w trybie “podgląd” w przeglądarce. Aby od razu zapisać plik na dysku należy określić nazwę pliku:

Generowanie pdf możemy takze wywołać wskazując odpowiednią akcję, partial view lub URL:


Wiem, że Rotativa to nie jedyne rozwiązanie tego typu. Innym wrapperem jest TuesPechkin. Niestety nie miałem jeszcze okazji go używać. Na pewno postaram się testowo coś zaimplementować przy jego użyciu, a wnioski przedstawię jako rozszerzenie tego wpisu.

Na pewno dla wielu rozwiązań użycie wkhtmltopdf posiada jeden znaczący minus – konieczność uruchamiania procesu po stronie serwera. W przypadku projektów, które realizowałem nie był to problem, a możliwości tego narzędzia w zupełności wystarczały do generowania różnego rodzaju dokumentów pdf, stąd “zaprzyjaźniłem” się z nim mocno 🙂

A czy Wy macie jakieś wnioski/opinie dotyczące wkhtmltopdf lub wrapperów ? A może znacie lepsze narzędzie godne uwagi?

Z chęcią poznam Wasze opinie. Zapraszam do komentowania.


Spodobał Ci się wpis? Podbij ↑

Author:

Programista, przedsiębiorca, tancerz ognia. Staram się ogarniać rzeczywistość wyciągając jak najwięcej wartości z tego co daje nam technologia. Jestem miłośnikiem produktywności i wyznawcą stwierdzenia "Done is better than perfect". Od ponad 5 lat staram rozwijać się oraz zdobywać doświadczenie jako programista. Najbliżej mi do aplikacji webowych i technologii .NET, ale od jakiegoś czasu stałem się entuzjastą rozwiązań JavaScriptowych.