fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
4 minut

Generowanie plików PDF


13.01.2014

Wiele aplikacji wymaga generowanie dokumentów PDF – i dobrze, bo są fajne. Gdy jednak programista rzucony zostaje w całe wzburzone morze możliwych do zastosowania rozwiązań, bo nie jest już tak wesoło.

Kiedyś było prosto: brało się iTextSharp i wsio. Jednak od paru lat (?) licencja tego komponentu się zmieniła, i ja w sumie sam nie wiem kiedy można a kiedy nie można go używać oraz ile to kosztuje. Z niego korzystają inne dostępne rozwiązania, takie chociażby jak ciekawie wyglądający RazorPDF for MVC. A przecież nie chcemy licencji łamać, nie? Można rozejrzeć się także za płatnymi produktami, jak TallComponents.

Ja podczas researchu niechcący na blogu mojego brata, jeszcze z czasów konkursu Daj Się Poznać, natknąłem się na komentarz Gutka. Ot, przypadek! Gutek podpowiedział, że do generowania PDF można wykorzystać Reporting Services, nawet nie mając żadnego webserwisu czy sqla. Spróbowałem. Wyszło. Ba, okazało się to banalnie proste! Jest to o tyle fajne, że nie muszę niczego “rysować” w kodzie. Co jak co, ale do projektowania wyglądu PDFa designer to rzecz zdecydowanie pożądana (o czym można się zresztą przekonać zerkając na podlinkowany post).

A jak to osiągnąć?

Ja robiłem aplikację konsolową, ale pewnie podobnie proste jest to i w innych typach programów. Po pierwsze, dodałem do projektu New Item i z zakładki “Reporting” wybrałem Report Wizard:

clip_image001

Sam wizard nie jest banalny jeśli nie miało się z tym wcześniej do czynienia, ale na pewno każdy go bez większych problemów ogarnie w paręnaście minut. Wystarczy podać źródło danych (u mnie to był obiekt), porozrzucać kontrolki po powierzchni i tyle.

Dopiero później zaczęła się zabawa – dość ciężko było w necie znaleźć jakiś sensowny tutorial pokazujący jak, bez pośrednictwa zdalnej usługi renderującej raporty, stworzyć sobie PDFa. Oto co mi wyszło trochę metodą prób i błędów:

  1. plik definicji raportu (*.rdlc) oznaczamy we właściwościach jako “embedded resource” (to jest chyba nawet domyślna opcja); zamiast tego można wykorzystać fizyczny plik na dysku, ale nie lubię takich śmieci i w miarę możliwości staram się wrzucać do assembly wszystko co mi potrzebne; wada: zmiana w wyglądzie PDFa będzie wymagała rekomplikacji projektu
  2. szykujemy metodę, która nam ten plik wyłuska ze skompilowanego assembly (ja robię tak jak poniżej żeby nie babrać się w strukturze katalogów i przestrzeni nazw, IYKWIM):
  3. Stream get_report_definition()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        var definitionName = assembly.GetManifestResourceNames()
            .Single(x => x.EndsWith("PdfDefinition.rdlc"));
     
        return assembly.GetManifestResourceStream(definitionName);
    }
    
  4. dodajemy referencje do Microsoft.ReportViewer.WinForms, System.Windows.Forms i System.XML
  5. implementujemy logikę generującą… PDFa, a cóżby innego:
  6. public byte[] GeneratePdf(PdfSource data)
    {
        using (var localReport = new LocalReport())
        {
            using (Stream reportDefinition = get_report_definition())
            {
                localReport.LoadReportDefinition(reportDefinition);
            }
     
            string reportDataSourceName = localReport.GetDataSourceNames()[0];
            var dataSource = new ReportDataSource(reportDataSourceName, new[] { data });
            localReport.DataSources.Add(dataSource);
     
            byte[] pdfBytes = localReport.Render("PDF");
     
            return pdfBytes;
        }
    }
    

    I już.

    PdfSource to klasa podana jako źródło danych w wizardzie odpalanym przy dodawaniu raportu do projektu.

    Ta konstrukcja:

    localReport.GetDataSourceNames()[0]
    

    pozwala mi uniezależnić się od nazwy wpisanej w wizardzie, bo od razu po jej wpisaniu zapomniałem jaka ona była.

    Obiekt z danymi podaję jako tablicę – bo tak trzeba (a pewnie w wielu przypadkach jest to nawet przydatne).

    Na koniec renderuję raport przekazując “PDF” jako oczekiwany format.

    Wsio. Działa. Teraz zostaje tylko uczynić ten plik “pięknym”, co jest zdecydowanie najtrudniejszą częścią całego zadania.

0 0 votes
Article Rating
13 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
pawelek
10 years ago

U nas przyjęło się, że raporty od dawien dawna były w htmlu. Potem było to drukowane poprzez drukarkę tworzącą pdf’y – novaPDF. Ale ostatnio zmieniono to używają wkhtmltopdf. Fajna biblioteka. Więc wygląd tworzysz sobie za pomocą htmla, a potem tylko to konwertujesz. Bierze pod uwagę css, wiec wsio może wyglądać tak jak lubisz :)

Robin
Robin
10 years ago

Fajny patent :)
A jak można wykoncypować rozwiązanie, które taki raport (PDF czy RS) wyśle od razu na zdefiniowaną lub domyślną drukarkę?

Tome
10 years ago

Ano .. rozwiązanie znane i używane (w jednym z projektów przy którym akurta nie pracowałeś :) ). Należy tylko pamiętać że przy wdrożeniu tegoż tam gdzie będzie to używane trzeba zainstalować SQL RS runtime.

Tam gdzie to używamy PDF ląduje w końcu jako dokument na faksie (ale poprzez bramkę SMTP).

Novakov
Novakov
10 years ago

Robiłem duży raport w reporting services (typu długi dokument z podsumowaniem zebranych danych, a nie prosta tabelka) i było z tym dużo problemu – puste strony, problem z utrzymaniem tabelki w kupie, więc ostrzegam przed używaniem RS do tego typu zastosowań (proste tabelki są ok).

Innym rozwiązaniem jest Apache FOP + XSL-FO. XSL-FO można generować przy pomocy XSLT albo Razora, a sam Apache FOP odpalić jako nowy proces albo przekonwertować na CLR przy pomocy IKVM.net

PiotrB
10 years ago

Po latach złych doświadczeń z Crystal Reports, później z Reporting Services, mój wybór padł na pdfsharp.
http://www.pdfsharp.net/

trackback
10 years ago

Generowanie plików PDF | Maciej Aniserowicz o programowaniu…

Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl…

jedmac
10 years ago

Do tej pory korzystałem z 2 rozwiązań – Syncfusion oraz ABCPdf. Jedno i drugie ma swoje zalety. Ogólnie przy generowaniu zwykłych pdfów, które zawierają tekst i obrazki nie ma żadnego problemu w jakimkolwiek rozwiązaniu. Schody zaczynają się w momencie, gdy musimy przygotować rozwiązanie z combobox’ami, list’ami itp. i dokument ma być później edytowalny ze zwykłego viewer’a tj. Adobe Reader/Foxit Reader. W momencie, gdy tworzymy taki dokument i wiemy, że się nie zmieni (tak jak wzorzec dla PIT np.) – jesteśmy w stanie to w miarę szybko osiągnąć. Natomaist jest jeszcze jedna sytuacja, z którą musiałem się zmierzyć – mieliśmy formularze HTML, które w zależności od kliknietych opcji rozszerzały się, bądź zwijały. Po kliknięciu przycisku “Send”, na podstawie formularza HTML renderowaliśmy formularz PDF ze wszystkimi interaktywnymi opcjami. Niestety, okazało się, że nie można w locie nadawać full-rights dokumentom, aby można je było później otworzyć w zwykłym view’erze. I tu są 2 opcje:

– albo rzeczywiście jako wymóg stawiamy klientowi posiadanie Adobe Acrobat
– albo korzystamy z całej infrastruktury firmy Adobe (z tego co pamiętam to był to kosmiczny koszt)

To taka mała dygresja na temat PDF :) Do zwykłych PDF’ów też jak najbardziej polecam Reporting Services.

Dario
Dario
10 years ago

Od lat niezmiennie polecam wkhtmlpdf. Htmla i Cssa zna chyba każdy :)
http://devpytania.pl/questions/3997/drukowanie-pdf-biblioteki/4009

Jackowy
Jackowy
10 years ago

PiotrB podał bardzo ciekawą alternatywę, pdfsharp. Pisze się znacznie wygodniej niż w iTextSharp, natomiast istnieje problem z czasem renderowania bardzo dużych tabel – problem, który istnieje od dłuższego czasu i nie został wciąż rozwiązany. Poza tym mankamentem, polecam :)

Adam
10 years ago

Przyłączam się do osób polecających PdfSharp. Nie jednego pdf’a w tym robiłem i uważam, że jest świetny i łatwy w użyciu :)

Jacek
Jacek
10 years ago

W ostatnim dużym projekcie gdzie trzeba było przetwarzać Pdf lub generować je z dokumentów Word miałem okazję korzystać z zestawu bibliotek Aspose. Niestety nie są tanie ale w porwaniu do wszystkiego innego z czego korzystałem pisanie na nich to czysta przyjemność. Człowiek przestaje walczyć z formatem a zaczyna z problemem.

GrzegorzL
GrzegorzL
10 years ago

Chyba zacznę pisać bloga, może wtedy zamiast od Gutka dowiedziałbyś się tego ode mnie ;P Sprawdziłem w starych projektach i już w 2008 z powodzeniem używałem tej metody korzystając z dołączonej do VS darmowej wersji CristalReports (generowane były pliki .rpt). Wtedy trzeba było przy deploymencie instalować runtime’a CR, co – jeśli dobrze pamietam – nie było takie łatwe, bo były jakieś problemy z wersjami bibliotek itp. Teraz z rdlc jest o wiele przyjemniej :)

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również