ConformanceTestDocument.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. using QuestPDF.Fluent;
  2. using QuestPDF.Helpers;
  3. using QuestPDF.Infrastructure;
  4. namespace QuestPDF.ConformanceTests;
  5. class ConformanceTestDocument : IDocument
  6. {
  7. private TextStyle TextStyleHeader1 = TextStyle.Default.FontSize(24).Bold().FontColor(Colors.Blue.Darken4);
  8. private TextStyle TextStyleHeader2 = TextStyle.Default.FontSize(18).Bold().FontColor(Colors.Blue.Darken2);
  9. private TextStyle TextStyleHeader3 = TextStyle.Default.FontSize(14).Bold().FontColor(Colors.Blue.Medium);
  10. public DocumentMetadata GetMetadata()
  11. {
  12. return new DocumentMetadata
  13. {
  14. Language = "en-US",
  15. Title = "Conformance Test"
  16. };
  17. }
  18. public DocumentSettings GetSettings()
  19. {
  20. return new DocumentSettings
  21. {
  22. PDFA_Conformance = PDFA_Conformance.PDFA_3A,
  23. PDFUA_Conformance = PDFUA_Conformance.PDFUA_1,
  24. };
  25. }
  26. public void Compose(IDocumentContainer container)
  27. {
  28. container.Page(page =>
  29. {
  30. page.Size(PageSizes.A4);
  31. page.Margin(40);
  32. page.Header()
  33. .Column(column =>
  34. {
  35. column.Item()
  36. .SemanticHeader1()
  37. .Text("Conformance Test")
  38. .Style(TextStyleHeader1);
  39. });
  40. page.Content()
  41. .PaddingVertical(20)
  42. .Column(column =>
  43. {
  44. column.Item()
  45. .SemanticSection()
  46. .Element(TableOfContentsSection);
  47. column.Item().PageBreak();
  48. column.Item()
  49. .SemanticSection()
  50. .Section("section-text")
  51. .Element(TextSection);
  52. column.Item().PageBreak();
  53. column.Item()
  54. .SemanticSection()
  55. .Section("section-styled-box")
  56. .Element(StyledBoxSection);
  57. column.Item().PageBreak();
  58. column.Item()
  59. .SemanticSection()
  60. .Section("section-styled-line")
  61. .Element(StyledLineSection);
  62. column.Item().PageBreak();
  63. column.Item()
  64. .SemanticSection()
  65. .Section("section-image")
  66. .Element(ImageSection);
  67. column.Item().PageBreak();
  68. column.Item()
  69. .SemanticSection()
  70. .Section("section-svg")
  71. .Element(SvgSection);
  72. column.Item().PageBreak();
  73. column.Item()
  74. .SemanticSection()
  75. .Section("section-list")
  76. .Element(ListSection);
  77. column.Item().PageBreak();
  78. column.Item()
  79. .SemanticSection()
  80. .Section("section-table-table")
  81. .Element(SimpleTableSection);
  82. column.Item().PageBreak();
  83. column.Item()
  84. .SemanticSection()
  85. .Section("section-table-vertical-headers")
  86. .Element(TableWithVerticalHeadersSection);
  87. column.Item().PageBreak();
  88. column.Item()
  89. .SemanticSection()
  90. .Section("section-table-horizontal-headers")
  91. .Element(TableWithHorizontalHeadersSection);
  92. column.Item().PageBreak();
  93. column.Item()
  94. .SemanticSection()
  95. .Section("section-table-spanning-cells")
  96. .Element(TableWithSpanningCellsSection);
  97. });
  98. page.Footer()
  99. .AlignCenter()
  100. .Text(text =>
  101. {
  102. text.Span("Page ");
  103. text.CurrentPageNumber();
  104. text.Span(" of ");
  105. text.TotalPages();
  106. });
  107. });
  108. }
  109. private void TableOfContentsSection(IContainer container)
  110. {
  111. container.Column(column =>
  112. {
  113. column.Spacing(6);
  114. column.Item()
  115. .SemanticHeader2()
  116. .Text("Table of Contents")
  117. .Style(TextStyleHeader2);
  118. column.Item()
  119. .SemanticTableOfContents()
  120. .Column(toc =>
  121. {
  122. void TocItem(string title, string sectionId)
  123. {
  124. toc.Item()
  125. .SemanticTableOfContentsItem()
  126. .Row(row =>
  127. {
  128. row.RelativeItem()
  129. .SemanticLink($"Go to {title}")
  130. .Text(text =>
  131. {
  132. text.SectionLink(title, sectionId).Underline();
  133. });
  134. row.ConstantItem(80)
  135. .AlignRight()
  136. .Text(text =>
  137. {
  138. text.Span("page ");
  139. text.BeginPageNumberOfSection(sectionId);
  140. });
  141. });
  142. }
  143. TocItem("Text", "section-text");
  144. TocItem("Styled Box", "section-styled-box");
  145. TocItem("Styled Line", "section-styled-line");
  146. TocItem("Images", "section-image");
  147. TocItem("SVG Content", "section-svg");
  148. TocItem("List", "section-list");
  149. TocItem("Simple Table", "section-table-table");
  150. TocItem("Table With Vertical Headers", "section-table-vertical-headers");
  151. TocItem("Table With Horizontal Headers", "section-table-horizontal-headers");
  152. TocItem("Table With Spanning Cells", "section-table-spanning-cells");
  153. });
  154. });
  155. }
  156. private void TextSection(IContainer container)
  157. {
  158. container.Column(column =>
  159. {
  160. column.Spacing(10);
  161. column.Item()
  162. .SemanticHeader2()
  163. .Text("Text")
  164. .Style(TextStyleHeader2);
  165. column.Item()
  166. .SemanticParagraph()
  167. .Text(text =>
  168. {
  169. text.Span("This is a semantic paragraph with ");
  170. text.Span("bold").Style(TextStyle.Default.Bold());
  171. text.Span(" and ");
  172. text.Span("italic").Style(TextStyle.Default.Italic());
  173. text.Span(" styles. ");
  174. text.Span(Placeholders.Sentence());
  175. });
  176. column.Item()
  177. .SemanticParagraph()
  178. .Text(text =>
  179. {
  180. text.Span(Placeholders.Paragraph());
  181. });
  182. column.Item()
  183. .SemanticHeader3()
  184. .Text("Multilingual and Links")
  185. .Style(TextStyleHeader3);
  186. column.Item()
  187. .SemanticLanguage("pl-PL")
  188. .SemanticParagraph()
  189. .Text("Zażółć gęślą jaźń");
  190. column.Item()
  191. .SemanticBlockQuotation()
  192. .PaddingLeft(10)
  193. .BorderLeft(2)
  194. .BorderColor(Colors.Grey.Lighten2)
  195. .SemanticParagraph()
  196. .Text(text => text.Span("\"A block-level quotation illustrating semantic tagging.\""));
  197. column.Item()
  198. .SemanticParagraph()
  199. .SemanticLink("QuestPDF website")
  200. .Text(t =>
  201. {
  202. t.Span("Visit ");
  203. t.Hyperlink("questpdf.com", "https://www.questpdf.com");
  204. t.Span(" for documentation.");
  205. });
  206. column.Item()
  207. .SemanticParagraph()
  208. .Text(t =>
  209. {
  210. t.Span("Inline code example: ");
  211. t.Element(e => e.SemanticCode()
  212. .Background(Colors.Grey.Lighten3)
  213. .PaddingHorizontal(4)
  214. .PaddingVertical(2)
  215. .Text("var x = 1;")
  216. );
  217. });
  218. });
  219. }
  220. private void StyledBoxSection(IContainer container)
  221. {
  222. container.Column(column =>
  223. {
  224. column.Spacing(10);
  225. column.Item()
  226. .SemanticHeader2()
  227. .Text("Styled Box")
  228. .Style(TextStyleHeader2);
  229. column.Item()
  230. .SemanticDivision()
  231. .Background(Colors.Grey.Lighten4)
  232. .Border(1)
  233. .BorderColor(Colors.Grey.Darken2)
  234. .Padding(12)
  235. .Column(box =>
  236. {
  237. box.Spacing(6);
  238. box.Item().Text(Placeholders.Paragraph());
  239. box.Item().Text(Placeholders.Sentence());
  240. box.Item()
  241. .SemanticCaption()
  242. .Text("Figure 1. A styled division used as a callout/caption.");
  243. });
  244. });
  245. }
  246. private void StyledLineSection(IContainer container)
  247. {
  248. container.Column(column =>
  249. {
  250. column.Spacing(10);
  251. column.Item()
  252. .SemanticHeader2()
  253. .Text("Styled Line")
  254. .Style(TextStyleHeader2);
  255. column.Item()
  256. .SemanticDivision()
  257. .Column(lines =>
  258. {
  259. lines.Spacing(6);
  260. lines.Item().SemanticCaption().Text("Thin solid line");
  261. lines.Item().LineHorizontal(1).LineColor(Colors.Blue.Medium);
  262. lines.Item().SemanticCaption().Text("Dashed gradient line");
  263. lines.Item().LineHorizontal(3)
  264. .LineDashPattern(new float[] { 3, 3 })
  265. .LineGradient(new[] { Colors.Red.Medium, Colors.Orange.Medium });
  266. });
  267. });
  268. }
  269. private void ImageSection(IContainer container)
  270. {
  271. container.Column(column =>
  272. {
  273. column.Spacing(10);
  274. column.Item()
  275. .SemanticHeader2()
  276. .Text("Images")
  277. .Style(TextStyleHeader2);
  278. var imageData = Placeholders.Image(480, 180);
  279. column.Item()
  280. .SemanticImage("A generated placeholder raster image")
  281. .Border(1)
  282. .BorderColor(Colors.Grey.Lighten1)
  283. .Padding(2)
  284. .Image(imageData)
  285. .FitArea();
  286. column.Item()
  287. .SemanticCaption()
  288. .Text("Figure 2. Placeholder image with alt text and caption.");
  289. });
  290. }
  291. private void SvgSection(IContainer container)
  292. {
  293. container.Column(column =>
  294. {
  295. column.Spacing(10);
  296. column.Item()
  297. .SemanticHeader2()
  298. .Text("SVG Content")
  299. .Style(TextStyleHeader2);
  300. var svg = "<svg xmlns='http://www.w3.org/2000/svg' width='400' height='120' viewBox='0 0 400 120'>" +
  301. "<rect x='5' y='5' width='390' height='110' rx='12' ry='12' fill='#E3F2FD' stroke='#64B5F6' stroke-width='2'/>" +
  302. "<circle cx='80' cy='60' r='35' fill='#90CAF9' stroke='#1E88E5' stroke-width='2'/>" +
  303. "<text x='140' y='68' font-family='Arial' font-size='20' fill='#0D47A1'>Scalable Vector Graphic</text>" +
  304. "</svg>";
  305. column.Item()
  306. .SemanticFigure("An example SVG graphic")
  307. .Border(1)
  308. .BorderColor(Colors.Grey.Lighten1)
  309. .Padding(2)
  310. .Svg(svg)
  311. .FitArea();
  312. column.Item()
  313. .SemanticCaption()
  314. .Text("Figure 3. Simple inline SVG with a caption.");
  315. });
  316. }
  317. private void ListSection(IContainer container)
  318. {
  319. container.Column(column =>
  320. {
  321. column.Spacing(10);
  322. column.Item()
  323. .SemanticHeader2()
  324. .Text("List")
  325. .Style(TextStyleHeader2);
  326. // Simple bulleted list with nested items and proper semantics
  327. column.Item()
  328. .SemanticList()
  329. .Column(list =>
  330. {
  331. // Item 1
  332. list.Item()
  333. .SemanticListItem()
  334. .Row(row =>
  335. {
  336. row.ConstantItem(16)
  337. .AlignCenter()
  338. .SemanticListLabel()
  339. .Text("•");
  340. row.RelativeItem()
  341. .SemanticListItemBody()
  342. .SemanticParagraph()
  343. .Text(Placeholders.Sentence());
  344. });
  345. // Item 2 with nested list
  346. list.Item()
  347. .SemanticListItem()
  348. .Column(item =>
  349. {
  350. item.Item()
  351. .Row(row =>
  352. {
  353. row.ConstantItem(16)
  354. .AlignCenter()
  355. .SemanticListLabel()
  356. .Text("•");
  357. row.RelativeItem()
  358. .SemanticListItemBody()
  359. .SemanticParagraph()
  360. .Text("Parent item with a nested list:");
  361. });
  362. // nested list
  363. item.Item()
  364. .PaddingLeft(20)
  365. .SemanticList()
  366. .Column(nested =>
  367. {
  368. nested.Item()
  369. .SemanticListItem()
  370. .Row(r =>
  371. {
  372. r.ConstantItem(16).AlignCenter().SemanticListLabel().Text("–");
  373. r.RelativeItem().SemanticListItemBody().SemanticParagraph().Text(Placeholders.Sentence());
  374. });
  375. nested.Item()
  376. .SemanticListItem()
  377. .Row(r =>
  378. {
  379. r.ConstantItem(16).AlignCenter().SemanticListLabel().Text("–");
  380. r.RelativeItem().SemanticListItemBody().SemanticParagraph().Text(Placeholders.Sentence());
  381. });
  382. });
  383. });
  384. // Item 3
  385. list.Item()
  386. .SemanticListItem()
  387. .Row(row =>
  388. {
  389. row.ConstantItem(16).AlignCenter().SemanticListLabel().Text("•");
  390. row.RelativeItem().SemanticListItemBody().SemanticParagraph().Text(Placeholders.Sentence());
  391. });
  392. });
  393. });
  394. }
  395. private void SimpleTableSection(IContainer container)
  396. {
  397. container.Column(column =>
  398. {
  399. column.Spacing(10);
  400. column.Item()
  401. .SemanticHeader2()
  402. .Text("Simple Table")
  403. .Style(TextStyleHeader2);
  404. column.Item()
  405. .SemanticTable()
  406. .Border(1)
  407. .BorderColor(Colors.Grey.Lighten2)
  408. .Padding(2)
  409. .Table(table =>
  410. {
  411. table.ApplySemanticTags();
  412. table.ColumnsDefinition(cols =>
  413. {
  414. cols.RelativeColumn(3);
  415. cols.RelativeColumn(1);
  416. cols.RelativeColumn(1);
  417. });
  418. table.Header(header =>
  419. {
  420. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).Text("Product").Style(TextStyle.Default.Bold());
  421. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).AlignRight().Text("Qty").Style(TextStyle.Default.Bold());
  422. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).AlignRight().Text("Price").Style(TextStyle.Default.Bold());
  423. });
  424. for (int i = 0; i < 6; i++)
  425. {
  426. table.Cell().Padding(6).Text(Placeholders.Label());
  427. table.Cell().Padding(6).AlignRight().Text((i + 1).ToString());
  428. table.Cell().Padding(6).AlignRight().Text(Placeholders.Price());
  429. }
  430. });
  431. });
  432. }
  433. private void TableWithVerticalHeadersSection(IContainer container)
  434. {
  435. container.Column(column =>
  436. {
  437. column.Spacing(10);
  438. column.Item()
  439. .SemanticHeader2()
  440. .Text("Table With Vertical Headers")
  441. .Style(TextStyleHeader2);
  442. column.Item()
  443. .SemanticTable()
  444. .Border(1)
  445. .BorderColor(Colors.Grey.Lighten2)
  446. .Padding(2)
  447. .Table(table =>
  448. {
  449. table.ApplySemanticTags();
  450. table.ColumnsDefinition(cols =>
  451. {
  452. cols.RelativeColumn(2); // row headers
  453. cols.RelativeColumn(1);
  454. cols.RelativeColumn(1);
  455. cols.RelativeColumn(1);
  456. });
  457. // top header row
  458. table.Header(header =>
  459. {
  460. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).Text("");
  461. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q1").Style(TextStyle.Default.Bold());
  462. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q2").Style(TextStyle.Default.Bold());
  463. header.Cell().Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q3").Style(TextStyle.Default.Bold());
  464. });
  465. string[] regions = { "North", "South", "East", "West" };
  466. foreach (var region in regions)
  467. {
  468. table.Cell().AsSemanticHorizontalHeader().Padding(6).Background(Colors.Grey.Lighten4).Text(region).Style(TextStyle.Default.Bold());
  469. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  470. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  471. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  472. }
  473. });
  474. });
  475. }
  476. private void TableWithHorizontalHeadersSection(IContainer container)
  477. {
  478. container.Column(column =>
  479. {
  480. column.Spacing(10);
  481. column.Item()
  482. .SemanticHeader2()
  483. .Text("Table With Horizontal Headers")
  484. .Style(TextStyleHeader2);
  485. column.Item()
  486. .SemanticTable()
  487. .Border(1)
  488. .BorderColor(Colors.Grey.Lighten2)
  489. .Padding(2)
  490. .Table(table =>
  491. {
  492. table.ApplySemanticTags();
  493. table.ColumnsDefinition(cols =>
  494. {
  495. cols.RelativeColumn(2); // metric
  496. cols.RelativeColumn(1);
  497. cols.RelativeColumn(1);
  498. cols.RelativeColumn(1);
  499. });
  500. table.Header(header =>
  501. {
  502. // first header row
  503. header.Cell().Row(1).Column(1).ColumnSpan(4).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Quarterly Sales").Style(TextStyle.Default.Bold());
  504. // second header row
  505. header.Cell().Row(2).Column(1).Padding(6).Background(Colors.Grey.Lighten3).Text("Metric").Style(TextStyle.Default.Bold());
  506. header.Cell().Row(2).Column(2).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q1").Style(TextStyle.Default.Bold());
  507. header.Cell().Row(2).Column(3).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q2").Style(TextStyle.Default.Bold());
  508. header.Cell().Row(2).Column(4).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Q3").Style(TextStyle.Default.Bold());
  509. });
  510. string[] metrics = { "Revenue", "Units", "Growth" };
  511. foreach (var m in metrics)
  512. {
  513. table.Cell().Padding(6).Text(m);
  514. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  515. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  516. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  517. }
  518. });
  519. });
  520. }
  521. private void TableWithSpanningCellsSection(IContainer container)
  522. {
  523. container.Column(column =>
  524. {
  525. column.Spacing(10);
  526. column.Item()
  527. .SemanticHeader2()
  528. .Text("Table With Spanning Cells")
  529. .Style(TextStyleHeader2);
  530. column.Item()
  531. .SemanticTable()
  532. .Border(1)
  533. .BorderColor(Colors.Grey.Lighten2)
  534. .Padding(2)
  535. .Table(table =>
  536. {
  537. table.ApplySemanticTags();
  538. table.ColumnsDefinition(cols =>
  539. {
  540. cols.RelativeColumn(2); // Category / Row header
  541. cols.RelativeColumn(1);
  542. cols.RelativeColumn(1);
  543. cols.RelativeColumn(1);
  544. });
  545. // Complex header: Category | Metrics (Min, Max) | Total
  546. table.Header(header =>
  547. {
  548. header.Cell().Row(1).Column(1).RowSpan(2).Padding(6).Background(Colors.Grey.Lighten3).Text("Category").Style(TextStyle.Default.Bold());
  549. header.Cell().Row(1).Column(2).ColumnSpan(2).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Metrics").Style(TextStyle.Default.Bold());
  550. header.Cell().Row(1).Column(4).RowSpan(2).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Total").Style(TextStyle.Default.Bold());
  551. header.Cell().Row(2).Column(2).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Min").Style(TextStyle.Default.Bold());
  552. header.Cell().Row(2).Column(3).Padding(6).Background(Colors.Grey.Lighten3).AlignCenter().Text("Max").Style(TextStyle.Default.Bold());
  553. });
  554. // Body with row spans
  555. string[] categories = { "Hardware", "Software" };
  556. foreach (var cat in categories)
  557. {
  558. // Category spans two subrows
  559. table.Cell().RowSpan(2).AsSemanticHorizontalHeader().Padding(6).Background(Colors.Grey.Lighten4).Text(cat).Style(TextStyle.Default.Bold());
  560. // first subrow
  561. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  562. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  563. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  564. // second subrow
  565. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  566. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  567. table.Cell().Padding(6).AlignRight().Text(Placeholders.Integer());
  568. }
  569. });
  570. });
  571. }
  572. }