Strona główna O mnie

PDFSharp i MigraDoc

Pierwsza publikacja tekstu: 6. września 2010 r.

Empira Software oferuje darmowe biblioteki służące do generowania plików PDF przez aplikacje korzystające z .NET framework. Pierwsza z nich, PDFsharp pozwala na niskopoziomowe tworzenie dokumentów, umożliwiając programiście kontrolę nad każdym rysowanym pikselem – podobnie jak ma to miejsce w przypadku interfejsu GDI+. MigraDoc operuje natomiast na wyższym poziomie abstrakcji, udostępniając klasy reprezentujące typowe elementy dokumentów znane z edytorów tekstu, m.in. akapity, tabele, wykresy, rozdziały itp. Biblioteka pozwala także generować dokumenty w formacie RTF oraz XPS; możliwe jest też wstawianie niskopoziomowych elementów PDFsharp-a do plików PDF tworzonych przez MigraDoc.

Przykładowy dokument z wykorzystaniem PDFSharp

Poniższy przykład demonstruje:

Pobierz kody źródłowe programów
using System;
using System.Diagnostics;
using System.Drawing;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Drawing.Layout;
using PdfSharp.Pdf;
using PdfSharp.Pdf.Security;
using PdfSharp.Pdf.Annotations;

namespace PDFExamples
{
	class Example1
	{
		public static void Main (string[] args)
		{
			/* Nazwa wynikowego pliku PDF */
			string filename = "example1.pdf";

			/* Utworzenie obiektu reprezentującego dokument PDF */
			PdfDocument document = new PdfDocument();

			/* Ustawianie informacji o dokumencie */
			PdfDocumentInformation docInfo = document.Info;

			docInfo.Author = "domas.pl"; // autor
			docInfo.Title = "Przykładowy dokument PDFSharp"; // tytuł

			/* Ustawianie opcji zabezpieczeń dokumentu */
			PdfSecuritySettings security = document.SecuritySettings;

			security.UserPassword = "user"; // hasło użytkownika
			security.OwnerPassword = "owner"; // hasło właściciela

			security.PermitModifyDocument = false; // zabraniamy modyfikacji
			security.PermitPrint = false; // zabraniamy drukowania
			security.PermitFullQualityPrint = false; // zabraniamy drukowania w pełnej jakości, łączy się z PermitPrint

			/* Dodanie strony do dokumentu */
			PdfPage page = document.AddPage();

			/* Utworzenie głównej zakładki dokumentu, pogrubionym tekstem w kolorze czerwonym */
			PdfOutline outline = document.Outlines.Add("Dokument", page, true, PdfOutlineStyle.Bold, XColors.Red);

			/* Pobranie kontekstu obszaru malowania strony */
			XGraphics gfx = XGraphics.FromPdfPage(page);

			/* Ustawianie opcje czcionek - kodowanie unicode oraz zagnieżdżanie czcionek stosowane zawsze - pozwala uniknąć problemów m.in. z polskimi ogonkami */
			XPdfFontOptions fontOptions = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always);

			/* Utworzenie pogrubionej czcionki typu times o rozmiarze 20pt */
			XFont fontTimes = new XFont("Times New Roman", 20.0f, XFontStyle.Bold, fontOptions);

			/* Utworzenie obiektu formatera który będzie rysował tekst */
			XTextFormatter textFormatter = new XTextFormatter(gfx);

			/* Rysowanie czarnego tekstu czcionką times w określonym obszarze kreślenia (obiekt XRect) */
			textFormatter.DrawString("Zażółć gęślą jaźń", fontTimes, XBrushes.Black,
			                         new XRect(64.0f, 64.0f, page.Width, page.Height), XStringFormat.TopLeft);

			XFont fontTahoma = new XFont("Tahoma", 36.0f, XFontStyle.Italic, fontOptions);

			textFormatter.DrawString("W Szczebrzeszynie chrząszcz brzmi w trzcinie", fontTahoma, XBrushes.Red,
			                         new XRect(60.0f, 128.0f, page.Width - 128.0f, page.Height),
			                         XStringFormat.TopLeft);

			/* Dodanie kolejnej strony do dokumentu */
			PdfPage page2 = document.AddPage();

			/* Dodanie podzakładki z odnośnikiem do drugiej strony - tekst kursywą w kolorze granatowym */
			outline.Outlines.Add("Druga strona", page2, true, PdfOutlineStyle.Italic, XColors.Navy);

			XGraphics gfx2 = XGraphics.FromPdfPage(page2);
			XTextFormatter textFormatter2 = new XTextFormatter(gfx2);
			XFont fontCourier = new XFont("Courier", 12.0f, XFontStyle.Regular);

			/* Zdefiniowanie obszaru prostokątnego w którym będzie rysowany tekst; parametry to kolejno pozycje X i Y, szerokość i wysokość */
			XRect textRect = new XRect(32.0f, 32.0f, page.Width / 2.0f - 32.0f, page.Height - 64.0f);

			/* Wypełnienie podanego obszaru błękitnym tłem z ciemnoniebieską ramką */
			gfx2.DrawRectangle(XPens.MidnightBlue, XBrushes.LightBlue, textRect);

			/* Wstawienie do niego tekstu */
			textFormatter2.DrawString(LoremIpsum.Generate(4), fontCourier, XBrushes.Blue,
			                         textRect, XStringFormat.TopLeft);

			/* Przykładowy element graficzny - "wykres kołowy" */
			gfx2.DrawPie(XPens.Black, XBrushes.Yellow, new Rectangle(340, 56, 200, 200), 30.0f, 310.0f);

			/* Adnotacja tekstowa */
			PdfTextAnnotation textAnnotation = new PdfTextAnnotation();
			textAnnotation.Title = "Komentarz do wykresu"; // tytuł
			textAnnotation.Subject = "Wykres"; // temat
			textAnnotation.Contents = "Pacman?"; // treść adnotacji
			textAnnotation.Icon = PdfTextAnnotationIcon.Note; // typ ikony widocznej na stronie
			textAnnotation.Color = XColors.LightYellow; // kolor pola adnotacji
			textAnnotation.Opacity = 0.75f; // przeźroczystość
			textAnnotation.Open = true; // adnotacja jest otwarta po otworzeniu dokumentu

			/* Położenie i rozmiar okna adnotacji - konieczne jest odwzorowanie prostokąta z przestrzeni świata na przestrzeń strony; adnotacja jest umieszczana względem jej dolnego lewego rogu */
			XRect annotationRect = gfx2.Transformer.WorldToDefaultPage(new XRect(new XPoint(340, 260), new XSize(30, 30)));
			textAnnotation.Rectangle = new PdfRectangle(annotationRect);

			/* Dodanie adnotacji do strony */
			page2.Annotations.Add(textAnnotation);

			/* Zapis dokumentu do pliku o podanej wcześniej nazwie */
			document.Save(filename);

			/* Otwarcie dokumentu w domyślnej przeglądarce */
			Process.Start(filename);
		}
	}
}

Klasa LoremIpsum służy do generowania tekstu wypełniającego dokument:

using System;
using System.Text;

namespace PDFExamples
{
	public class LoremIpsum
	{
		/* Funkcja zwraca ciąg znaków zawierający tekst "Lorem ipsum..." powielony zadaną ilość razy (http://pl.lipsum.com) */
		public static string Generate(int count)
		{
			string text = "Lorem ipsum dolor sit amet, consectetur adipisicing " +
				"elit, sed do eiusmod tempor incididunt ut labore et dolore magna " +
				"aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
				"laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
				"dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
				"fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
				"proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
				
			StringBuilder sb = new StringBuilder();
			
			for (int i = 0; i < count; i++)
			{
				if (i != 0)
				{
					sb.Append("\n");
				}
				sb.Append(text);
			}
			
			return sb.ToString();
		}
	}
}

Biblioteka pozwala nie tylko na tworzenie dokumentów, ale też ich edycję: łączenie, dzielenie, zabezpieczanie, wyciąganie obrazów. Przykłady takich zastosowań można znaleźć na stronie projektu.

Przykładowy dokument z zastosowaniem MigraDoc

Przykład demonstruje:

using System;
using System.Diagnostics;
using System.Text;
using PdfSharp.Pdf;
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.DocumentObjectModel.Shapes.Charts;
using MigraDoc.DocumentObjectModel.Shapes;

namespace PDFExamples
{
	class Example2
	{
		public static void Main(string[] args)
		{
			/* Nazwa wynikowego pliku PDF */
			string filename = "example2.pdf";

			/* Utworzenie nowego dokumentu */
			Document document = new Document();

			/* Dodanie nowej sekcji */
			Section section = document.AddSection();

			/* Ustawienie stylu domyślnego */
			Style style = document.Styles[StyleNames.Normal];
			style.Font.Name = "Times New Roman"; // nazwa czcionki
			style.ParagraphFormat.SpaceAfter = new Unit(0.75f, UnitType.Centimeter); // wolne miejsce po akapicie

			/* Ustawienie stylu tytułu poziomu pierwszego */
			style = document.Styles[StyleNames.Heading1];
			style.Font.Size = 24; // rozmiar czcionki

			/* Dodanie akapitu z tytułem do utworzonej sekcji */
			Paragraph paragraph = section.AddParagraph("Zażółć gęślą jaźń");
			paragraph.Style = StyleNames.Heading1; // styl akapitu
			paragraph.Format.Borders.Bottom.Color = Colors.Black; // czarna linia podkreślająca tekst na szerokość strony

			/* Dodanie akapitu z tekstem */
			paragraph = section.AddParagraph(LoremIpsum.Generate(1)); // normalna czcionka
			paragraph.Format.Alignment = ParagraphAlignment.Justify; // wyjustowanie tekstu
			paragraph.AddFormattedText(" " + LoremIpsum.Generate(1), TextFormat.Italic); // tekst kursywą
			paragraph.AddFormattedText(" " + LoremIpsum.Generate(1), TextFormat.Bold | TextFormat.Italic); // tekst pogrubioną kursywą

			/* Dodanie tekstu w ramce z kolorowym tłem */
			paragraph = section.AddParagraph(LoremIpsum.Generate(1));
			paragraph.Format.Shading.Color = Colors.LightBlue; // kolor wypełnienia
			paragraph.Format.Borders.Width = 0.5f; // grubość obramowania

			/* Utworzenie tabeli */
			MigraDoc.DocumentObjectModel.Tables.Table table = section.AddTable();
			table.Borders.Width = 0.75f; // grubość obramowania
			table.Format.Font.Color = Colors.White; // kolor czcionki

			/* Dodawanie kolumn do tabeli */
			Column column = table.AddColumn(Unit.FromCentimeter(5.0f));
			column.Format.Alignment = ParagraphAlignment.Right; // położenie tekstu
			column.Shading.Color = Colors.Red; // kolor wypełnienia komórek kolumny

			column = table.AddColumn(Unit.FromInch(2.0f));
			column.Format.Alignment = ParagraphAlignment.Center;
			column.Shading.Color = Colors.Green;

			column = table.AddColumn(Unit.FromMillimeter(50.0f));
			column.Format.Alignment = ParagraphAlignment.Left;
			column.Shading.Color = Colors.Blue;

			table.Rows.Height = 75.0f; // wysokość wierszy

			/* Dodawanie wierszy do tabeli */
			Row row = table.AddRow();
			row.VerticalAlignment = VerticalAlignment.Top;

			row.Cells[0].AddParagraph("red");
			row.Cells[1].AddParagraph("green");
			row.Cells[2].AddParagraph("blue");

			row = table.AddRow();
			row.VerticalAlignment = VerticalAlignment.Center;
			row.Cells[0].AddParagraph("1");
			row.Cells[0].MergeRight = 1; // komórka łączy się z jedną sąsiadującą komórką po prawej stronie
			row.Cells[0].MergeDown = 1; // komórka z sąsiednią komórką po prawej stronie łączy się z analogicznymi komórkami w dolnym wierszu
			row.Cells[1].AddParagraph("2");
			row.Cells[2].AddParagraph("3");

			row = table.AddRow();
			row.VerticalAlignment = VerticalAlignment.Bottom;
			row.Cells[0].AddParagraph("4");
			row.Cells[1].AddParagraph("5");
			row.Cells[2].AddParagraph("6");

			/* Utworzenie stopki */
			HeaderFooter footer = section.Footers.Primary;
			paragraph = footer.AddParagraph("Wygenerowano ");
			paragraph.AddDateField(); // dodanie pola daty i czasu

			/* Utworzenie nowej sekcji dokumentu */
			section = document.AddSection();

			/* Tytuł nowej sekcji */
			paragraph = section.AddParagraph("Wykres", "Heading1"); // tekst i jego styl
			paragraph.AddBookmark("Wykres"); // nowa zakładka dokumentu

			/* Utworzenie wykresu */
			Chart chart = section.AddChart();

			chart.Width = Unit.FromCentimeter(12.0f); // szerokość
			chart.Height = Unit.FromInch(2.5f); // wysokość

			/* Ustalenie pionowych serii danych */
			Series series = chart.SeriesCollection.AddSeries();
			series.Add(new double[] {1, 2, 7, 5, 13, 10}); // wartości
			series.ChartType = ChartType.Column2D; // rodzaj wykresu
			series.HasDataLabel = true; // rysuje etykiety

			/* Ustalenie poziomych serii danych */
			XSeries xseries = chart.XValues.AddXSeries();
			for (int i=1; i<7; i++)
				xseries.Add(i.ToString());

			chart.XAxis.Title.Caption = "Miesiąc"; // etykieta
			chart.XAxis.HasMajorGridlines = true; // rysuje poziome linie wykresu

			chart.YAxis.MajorTickMark = TickMarkType.Cross; // znacznik po obu stronach lewej krawędzi wykresu
			chart.YAxis.Title.Caption = "Sprzedaż";
			chart.YAxis.HasMajorGridlines = true; // rysuje pionowe linie wykresu

			paragraph = section.AddParagraph("Obrazek", "Heading1");

			/* Utworzenie obrazka z pliku */
			Image image = section.AddImage("pdfsharp.png");
			image.Width = "8cm"; // szerokość

			/* Utworzenie obiektu renderującego PDF */
			PdfDocumentRenderer pdfDocRenderer = new PdfDocumentRenderer(true, PdfFontEmbedding.Always); // obsługa unicode, zagnieżdżanie czcionek zawsze
			pdfDocRenderer.Document = document; // przypisanie dokumentu
			pdfDocRenderer.RenderDocument(); // renderowanie
			pdfDocRenderer.PdfDocument.Save(filename); // zapis

			/* Otwarcie dokumentu w domyślnej przeglądarce */
			Process.Start(filename);
		}
	}
}

Więcej przykładów do obejrzenia na stronie projektu.

Dunet Grzegorz Witek Jacek Rosik Michał Wróbel Radzio Yaras