Xaml2Pdf

Sample C# code for using Apryse SDK to dynamically generate PDF or XPS directly from a FlowDocument, XAML, or WPF. Converting XAML/FlowDocument to PDF is not only easy, but is also very flexible in terms of how content is paginated and flowed into a fixed document such as PDF or XPS. Learn more about our Server SDK and PDF Conversion Library.

1//
2// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
3//
4using System;
5using System.IO;
6using System.Windows;
7using System.Windows.Documents;
8using System.Windows.Media;
9using System.Xml;
10using System.Windows.Controls;
11using System.Windows.Markup;
12
13using pdftron;
14using pdftron.Common;
15using pdftron.SDF;
16using pdftron.PDF;
17using pdftron.Xaml;
18
19namespace Xaml2PdfTestCS
20{
21 /// <summary>
22 /// This sample shows how use pdftron.Xaml.Convert to convert .xaml files
23 /// into PDF documents with control over headers and footers, main body placement,
24 /// and column widths. Pagination is controlled by specifying the page size and
25 /// body size (margins) and all pages are appended to a PDFDoc which can then be
26 /// further manipulated using the PDFNet API.
27 ///
28 /// Three types of XAML objects are convertible using pdftron.Xaml.Convert:
29 /// - FlowDocument's which describe content that is reflowable from page to page
30 /// - FixedDocument's which describe content that has been placed on a fixed page
31 /// - Blocks such as Canvas, RichTextBox, Section etc which can be wrapped or inserted
32 /// directly into a FlowDocument
33 ///
34 /// This sample has three example uses of pdftron.Xaml.Convert:
35 /// - CreateXamlFlowDocumentFromCanvas() demonstrates how to read in a Canvas
36 /// described in a .xaml file and convert it to PDF.
37 /// - CreateXamlTableAndConvert() demonstrates how to programmatically create
38 /// a FlowDocument with a table, and then convert it to PDF as a single column
39 /// document.
40 /// - ConvertXamlFlowDocumentsFromFiles() demonstrates how to define functions to
41 /// create page headers and footers.
42 ///
43 /// Limitations:
44 /// Requires Microsoft .NET 3.5
45 ///
46 /// There are many Xaml classes that cannot be added to FlowDocument or FixedDocuments and
47 /// therefore this sample converter cannot convert Page, Window or Frame objects.
48 /// </summary>
49 class Program
50 {
51 private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
52 static Program() {}
53
54 // Relative path to the folder containing test files.
55 const string inputPath = "../../TestFiles/";
56 const string outputPath = "../../../../TestFiles/Output/";
57
58 /// <summary>
59 /// Entry point for the sample.
60 /// </summary>
61 /// <param name="args">command line arguments (ignored)</param>
62 [STAThread]
63 static void Main(string[] args)
64 {
65 PDFNet.Initialize(PDFTronLicense.Key);
66 try
67 {
68 CreateXamlFlowDocumentFromCanvas();
69 CreateXamlTableAndConvert();
70 ConvertXamlFlowDocumentsFromFiles();
71 }
72 catch (PDFNetException e)
73 {
74 Console.WriteLine(e.Message);
75 }
76 catch (Exception e)
77 {
78 Console.WriteLine(e.Message);
79 }
80 PDFNet.Terminate();
81 }
82
83 /// <summary>
84 /// Demonstrate how to load a Xaml file containing a Canvas and convert
85 /// it to PDF.
86 /// </summary>
87 static public void CreateXamlFlowDocumentFromCanvas()
88 {
89 // load the Xaml file containing the canvas
90 string rawXamlText = "";
91 using(StreamReader streamReader = File.OpenText(inputPath + "xamlshield.xaml"))
92 {
93 rawXamlText = streamReader.ReadToEnd();
94 }
95 StringReader stringReader = new StringReader(rawXamlText);
96 XmlReader xmlReader = XmlReader.Create(stringReader);
97 Canvas canvasImage = (Canvas)XamlReader.Load(xmlReader);
98
99 // Now convert to PDF
100 using (PDFDoc pdfdoc = new PDFDoc())
101 {
102 pdftron.Xaml.Convert.ToPdf(pdfdoc, canvasImage);
103 string outputFileName = outputPath + "xamlshield.pdf";
104 pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);
105
106 Console.WriteLine("Wrote " + outputFileName);
107 Console.WriteLine("Done.");
108 }
109 }
110
111 /// <summary>
112 /// Demonstrate how to create a Xaml table and convert it to
113 /// PDF. Also demonstrates how to use the ConverterOptions.NumColumns
114 /// setting to draw the table across the page, rather than across
115 /// the left column of a two column page.
116 /// </summary>
117 static public void CreateXamlTableAndConvert()
118 {
119 // from MSDN SDK Sample TableCsharpSample
120 FlowDocument flowDoc = new FlowDocument();
121
122 pdftron.Xaml.ConverterOptions options = new ConverterOptions();
123 options.NumColumns = 1;
124
125 // Create the Table...
126 Table table1 = new Table();
127 // ...and add it as a content element of the TextFlow.
128 flowDoc.Blocks.Add(table1);
129 // tf1.ContentStart.InsertTextElement(table1);
130
131 // Set some global formatting properties for the table.
132 table1.CellSpacing = 10;
133 table1.Background = Brushes.White;
134
135 // Create 6 columns and add them to the table's Columns collection.
136 int numberOfColumns = 6;
137 for (int x = 0; x < numberOfColumns; x++) table1.Columns.Add(new TableColumn());
138
139 // Set alternating background colors for the middle colums.
140 table1.Columns[1].Background =
141 table1.Columns[3].Background =
142 Brushes.LightSteelBlue;
143 table1.Columns[2].Background =
144 table1.Columns[4].Background =
145 Brushes.Beige;
146
147 // Create and add an empty TableRowGroup to hold the table's Rows.
148 table1.RowGroups.Add(new TableRowGroup());
149
150 // Add the first (title) row.
151 table1.RowGroups[0].Rows.Add(new TableRow());
152
153 // Alias the current working row for easy reference.
154 TableRow currentRow = table1.RowGroups[0].Rows[0];
155
156 // Global formatting for the title row.
157 currentRow.Background = Brushes.Silver;
158 currentRow.FontSize = 40;
159 currentRow.FontWeight = System.Windows.FontWeights.Bold;
160
161 // Add the header row with content,
162 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("2004 Sales Project"))));
163 // and set the row to span all 6 columns.
164 currentRow.Cells[0].ColumnSpan = 6;
165
166 // Add the second (header) row.
167 table1.RowGroups[0].Rows.Add(new TableRow());
168 currentRow = table1.RowGroups[0].Rows[1];
169
170 // Global formatting for the header row.
171 currentRow.FontSize = 18;
172 currentRow.FontWeight = FontWeights.Bold;
173
174 // Add cells with content to the second row.
175 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Product"))));
176 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 1"))));
177 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 2"))));
178 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 3"))));
179 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 4"))));
180 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("TOTAL"))));
181
182 table1.RowGroups[0].Rows.Add(new TableRow());
183 currentRow = table1.RowGroups[0].Rows[2];
184
185 // Global formatting for the row.
186 currentRow.FontSize = 12;
187 currentRow.FontWeight = FontWeights.Normal;
188
189 // Add cells with content to the third row.
190 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Widgets"))));
191 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$50,000"))));
192 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$55,000"))));
193 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$60,000"))));
194 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$65,000"))));
195 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$230,000"))));
196
197 // Bold the first cell.
198 currentRow.Cells[0].FontWeight = FontWeights.Bold;
199
200 // Add the fourth row.
201 table1.RowGroups[0].Rows.Add(new TableRow());
202 currentRow = table1.RowGroups[0].Rows[3];
203
204 // Global formatting for the row.
205 currentRow.FontSize = 12;
206 currentRow.FontWeight = FontWeights.Normal;
207
208 // Add cells with content to the third row.
209 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Wickets"))));
210 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$100,000"))));
211 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$120,000"))));
212 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$160,000"))));
213 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$200,000"))));
214 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$580,000"))));
215
216 // Bold the first cell.
217 currentRow.Cells[0].FontWeight = FontWeights.Bold;
218
219 table1.RowGroups[0].Rows.Add(new TableRow());
220 currentRow = table1.RowGroups[0].Rows[4];
221
222 // Global formatting for the footer row.
223 currentRow.Background = Brushes.LightGray;
224 currentRow.FontSize = 18;
225 currentRow.FontWeight = System.Windows.FontWeights.Normal;
226
227 // Add the header row with content,
228 currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Projected 2004 Revenue: $810,000"))));
229 // and set the row to span all 6 columns.
230 currentRow.Cells[0].ColumnSpan = 6;
231
232 // The PDFDoc to put the converted .xaml document into
233 using (PDFDoc pdfdoc = new PDFDoc())
234 {
235 pdftron.Xaml.Convert.ToPdf(pdfdoc, flowDoc, options );
236 string outputFileName = outputPath + "CreateXamlTableAndConvert.pdf";
237 pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);
238
239 Console.WriteLine("Wrote " + outputFileName);
240 Console.WriteLine("Done.");
241 }
242 }
243
244 /// <summary>
245 /// Demonstrate how to convert Xaml files directly from .xaml to .pdf
246 /// </summary>
247 static public void ConvertXamlFlowDocumentsFromFiles()
248 {
249 string[] inputFileNames = new string[] {"BobWatson.xaml",
250 "chocolate.xaml",
251 "FlowDocumentFormats.xaml",
252 "FlowDocumentSample1.xaml",
253 "FlowDocumentSample2.xaml",
254 "FlowDocumentSample3.xaml",
255 "MarkusEgger.xaml",
256 "MarkusEgger-withImageReference.xaml",
257 "RichTextBox.xaml",
258 "ThreeRectangles.xaml",
259 "WPFNotepad-1.xaml"};
260
261 foreach( string inputFileName in inputFileNames)
262 {
263 try
264 {
265 // The PDFDoc to put the converted .xaml document into
266 using (PDFDoc pdfdoc = new PDFDoc())
267 {
268
269 ConverterOptions options = new ConverterOptions();
270 options.HeaderFunc = new ConverterOptions.DrawHeaderFooter(MyDrawHeader);
271 options.FooterFunc = new ConverterOptions.DrawHeaderFooter(MyDrawFooter);
272
273 pdftron.Xaml.Convert.ToPdf(pdfdoc, inputPath + inputFileName, options);
274
275 // output the PDFDoc:
276 string outputFileName = inputFileName;
277 outputFileName = outputFileName.Remove(outputFileName.LastIndexOf('.')) + ".pdf";
278 outputFileName = outputPath + outputFileName;
279 pdfdoc.Save(outputFileName, SDFDoc.SaveOptions.e_linearized);
280
281 Console.WriteLine("Wrote " + outputFileName);
282 Console.WriteLine("Done.");
283 }
284 }
285 catch (PDFNetException e)
286 {
287 Console.WriteLine(e.Message);
288 Console.WriteLine("For file " + inputFileName);
289 }
290 catch (Exception e)
291 {
292 Console.WriteLine(e.Message);
293 Console.WriteLine("For file " + inputFileName);
294 }
295 }
296 }
297
298 /// <summary>
299 /// This variable hold the typeface resource used by the header and footer.
300 /// Any resource that you use in the header and footer delegates must persist
301 /// until the document is serialized.
302 /// </summary>
303 static Typeface typeface = null;
304
305 /// <summary>
306 /// Example Header delegate for ConverterOptions, used in ConvertXamlFlowDocumentsFromFiles()
307 /// </summary>
308 static public void MyDrawHeader(DrawingContext context, pdftron.PDF.Rect bounds,
309 pdftron.PDF.Rect bodyBounds, Size pageSize, int pageNumber)
310 {
311 // any resources that you use in the header and footer delegates must persist until the
312 // document is serialized
313 if (typeface == null)
314 {
315 typeface = new Typeface("Comic Sans MS");
316 }
317
318 //12 point text for header page number
319 FormattedText text = new FormattedText("Page " + (pageNumber + 1),
320 System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
321 typeface, 12, Brushes.Black);
322 // the translation applied to the page put the origin at the top left corner of the
323 // body rectangle. So negative y values move us out of the body into the top margin
324 context.DrawText(text, new System.Windows.Point(0, -bounds.y2));
325 }
326
327 /// <summary>
328 /// Example Footer delegate for ConverterOptions, used in ConvertXamlFlowDocumentsFromFiles()
329 /// </summary>
330 static public void MyDrawFooter(DrawingContext context, pdftron.PDF.Rect bounds,
331 pdftron.PDF.Rect bodyBounds, Size pageSize, int pageNumber)
332 {
333 // any resources that you use in the header and footer delegates must persist until the
334 // document is serialized
335 if (typeface == null)
336 {
337 typeface = new Typeface("Comic Sans MS");
338 }
339
340 //8 point text for footer in DarkGreen
341 FormattedText text = new FormattedText("This is the footer for page " + (pageNumber + 1),
342 System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
343 typeface, 8, Brushes.DarkGreen);
344
345 // The translation applied to the page puts the origin at the top left corner of the
346 // body rectangle, adjust.
347 context.DrawText(text, new System.Windows.Point(0, bounds.y1 - bodyBounds.y1));
348 }
349
350 }
351}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales