TextExamples.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. using System;
  2. using System.Linq;
  3. using System.Text;
  4. using NUnit.Framework;
  5. using QuestPDF.Elements.Text;
  6. using QuestPDF.Examples.Engine;
  7. using QuestPDF.Fluent;
  8. using QuestPDF.Helpers;
  9. using QuestPDF.Infrastructure;
  10. namespace QuestPDF.Examples
  11. {
  12. public class TextExamples
  13. {
  14. [Test]
  15. public void SimpleText()
  16. {
  17. RenderingTest
  18. .Create()
  19. .PageSize(500, 100)
  20. .ProduceImages()
  21. .ShowResults()
  22. .Render(container =>
  23. {
  24. container
  25. .Padding(5)
  26. .MinimalBox()
  27. .Border(1)
  28. .Padding(10)
  29. .Text(Placeholders.Paragraph());
  30. });
  31. }
  32. [Test]
  33. public void SimpleTextBlock()
  34. {
  35. RenderingTest
  36. .Create()
  37. .PageSize(600, 300)
  38. .ProduceImages()
  39. .ShowResults()
  40. .Render(container =>
  41. {
  42. container
  43. .Padding(5)
  44. .MinimalBox()
  45. .Border(1)
  46. .MaxWidth(300)
  47. .Padding(10)
  48. .Text(text =>
  49. {
  50. text.DefaultTextStyle(TextStyle.Default.FontSize(20));
  51. text.Span("This is a normal text, followed by an ");
  52. text.Span("underlined red text").FontColor(Colors.Red.Medium).Underline();
  53. text.Span(".");
  54. });
  55. });
  56. }
  57. [Test]
  58. public void TextWeight()
  59. {
  60. RenderingTest
  61. .Create()
  62. .PageSize(500, 500)
  63. .ProduceImages()
  64. .ShowResults()
  65. .Render(container =>
  66. {
  67. container
  68. .Padding(20)
  69. .MinimalBox()
  70. .Border(1)
  71. .Padding(20)
  72. .Text(text =>
  73. {
  74. text.DefaultTextStyle(x => x.FontFamily(Fonts.Calibri).FontSize(20));
  75. text.Line("Thin").Thin();
  76. text.Line("ExtraLight").ExtraLight();
  77. text.Line("Light").Light();
  78. text.Line("NormalWeight").NormalWeight();
  79. text.Line("Medium").Medium();
  80. text.Line("SemiBold").SemiBold();
  81. text.Line("Bold").Bold();
  82. text.Line("ExtraBold").ExtraBold();
  83. text.Line("Black").Black();
  84. text.Line("ExtraBlack").ExtraBlack();
  85. });
  86. });
  87. }
  88. [Test]
  89. public void LineHeight()
  90. {
  91. RenderingTest
  92. .Create()
  93. .PageSize(500, 700)
  94. .ProduceImages()
  95. .ShowResults()
  96. .Render(container =>
  97. {
  98. container
  99. .Padding(20)
  100. .Column(column =>
  101. {
  102. var lineHeights = new[] { 0.8f, 1f, 1.5f };
  103. var paragraph = Placeholders.Paragraph();
  104. foreach (var lineHeight in lineHeights)
  105. {
  106. column
  107. .Item()
  108. .Border(1)
  109. .Padding(10)
  110. .Text(paragraph)
  111. .FontSize(16)
  112. .LineHeight(lineHeight);
  113. }
  114. });
  115. });
  116. }
  117. [Test]
  118. public void LetterSpacing()
  119. {
  120. RenderingTest
  121. .Create()
  122. .PageSize(500, 700)
  123. .ProduceImages()
  124. .ShowResults()
  125. .Render(container =>
  126. {
  127. container
  128. .Padding(20)
  129. .Column(column =>
  130. {
  131. var letterSpacing = new[] { -1f, 0f, 2f };
  132. var paragraph = Placeholders.Sentence();
  133. foreach (var spacing in letterSpacing)
  134. {
  135. column
  136. .Item()
  137. .Border(1)
  138. .Padding(10)
  139. .Column(nestedColumn =>
  140. {
  141. nestedColumn.Item()
  142. .Text(paragraph)
  143. .FontSize(16)
  144. .LetterSpacing(spacing);
  145. nestedColumn.Item()
  146. .Text($"Letter spacing of {spacing} pt")
  147. .FontSize(10)
  148. .Italic()
  149. .FontColor(Colors.Blue.Medium);
  150. });
  151. }
  152. });
  153. });
  154. }
  155. [Test]
  156. public void SuperscriptSubscript_Simple()
  157. {
  158. RenderingTest
  159. .Create()
  160. .PageSize(500, 500)
  161. .ProduceImages()
  162. .ShowResults()
  163. .Render(container =>
  164. {
  165. container
  166. .Padding(20)
  167. .MinimalBox()
  168. .Border(1)
  169. .Padding(20)
  170. .Text(text =>
  171. {
  172. text.DefaultTextStyle(x => x.FontSize(20));
  173. text.ParagraphSpacing(10);
  174. var highlight = TextStyle.Default.BackgroundColor(Colors.Green.Lighten3);
  175. text.Span("E=mc").Style(highlight);
  176. text.Span("2").Superscript().Style(highlight);
  177. text.Span(" is the equation of mass–energy equivalence.");
  178. text.EmptyLine();
  179. text.Span("H").Style(highlight);
  180. text.Span("2").Subscript().Style(highlight);
  181. text.Span("O").Style(highlight);
  182. text.Span(" is the chemical formula for water.");
  183. });
  184. });
  185. }
  186. [Test]
  187. public void SuperscriptSubscript_Effects()
  188. {
  189. RenderingTest
  190. .Create()
  191. .PageSize(800, 400)
  192. .ProduceImages()
  193. .ShowResults()
  194. .Render(container =>
  195. {
  196. container
  197. .Padding(25)
  198. .DefaultTextStyle(x => x.FontSize(30))
  199. .Column(column =>
  200. {
  201. column.Spacing(25);
  202. column.Item().Text(text =>
  203. {
  204. text.DefaultTextStyle(x => x.Underline());
  205. text.Span("Underline of the superscript (E = mc");
  206. text.Span("2").Superscript();
  207. text.Span(") should be at the same height as for normal text.");
  208. });
  209. column.Item().Text(text =>
  210. {
  211. text.DefaultTextStyle(x => x.Underline());
  212. text.Span("Underline of the subscript(H");
  213. text.Span("2").Subscript();
  214. text.Span("O) should be slightly lower than a normal text.");
  215. });
  216. column.Item().Text(text =>
  217. {
  218. text.DefaultTextStyle(x => x.Strikethrough());
  219. text.Span("Strikethrough of both superscript (E=mc");
  220. text.Span("2").Superscript();
  221. text.Span(") and subscript(H");
  222. text.Span("2").Subscript();
  223. text.Span("O) should be visible in the middle of the text.");
  224. });
  225. });
  226. });
  227. }
  228. [Test]
  229. public void ParagraphSpacing()
  230. {
  231. RenderingTest
  232. .Create()
  233. .PageSize(500, 500)
  234. .ProduceImages()
  235. .ShowResults()
  236. .Render(container =>
  237. {
  238. container
  239. .Padding(5)
  240. .MinimalBox()
  241. .Border(1)
  242. .Padding(10)
  243. .Text(text =>
  244. {
  245. text.Line(Placeholders.Paragraph());
  246. });
  247. });
  248. }
  249. [Test]
  250. public void CustomElement()
  251. {
  252. RenderingTest
  253. .Create()
  254. .PageSize(500, 200)
  255. .ProduceImages()
  256. .ShowResults()
  257. .Render(container =>
  258. {
  259. container
  260. .Padding(5)
  261. .MinimalBox()
  262. .Border(1)
  263. .Padding(10)
  264. .Text(text =>
  265. {
  266. text.DefaultTextStyle(TextStyle.Default.FontSize(20));
  267. text.Span("This is a random image aligned to the baseline: ");
  268. text.Element()
  269. .PaddingBottom(-6)
  270. .Height(24)
  271. .Width(48)
  272. .Image(Placeholders.Image);
  273. text.Span(".");
  274. });
  275. });
  276. }
  277. [Test]
  278. public void TextElements()
  279. {
  280. RenderingTest
  281. .Create()
  282. .PageSize(PageSizes.A4)
  283. .ProducePdf()
  284. .ShowResults()
  285. .Render(container =>
  286. {
  287. container
  288. .Padding(20)
  289. .Padding(10)
  290. .MinimalBox()
  291. .Border(1)
  292. .Padding(5)
  293. .Padding(10)
  294. .Text(text =>
  295. {
  296. text.DefaultTextStyle(TextStyle.Default);
  297. text.AlignLeft();
  298. text.ParagraphSpacing(10);
  299. text.Line(Placeholders.LoremIpsum());
  300. text.Span($"This is target text that should show up. {DateTime.UtcNow:T} > This is a short sentence that will be wrapped into second line hopefully, right? <").Underline();
  301. });
  302. });
  303. }
  304. [Test]
  305. public void Textcolumn()
  306. {
  307. RenderingTest
  308. .Create()
  309. .PageSize(PageSizes.A4)
  310. .ProducePdf()
  311. .ShowResults()
  312. .Render(container =>
  313. {
  314. container
  315. .Padding(20)
  316. .Padding(10)
  317. .MinimalBox()
  318. .Border(1)
  319. .Padding(5)
  320. .Padding(10)
  321. .Text(text =>
  322. {
  323. text.DefaultTextStyle(TextStyle.Default);
  324. text.AlignLeft();
  325. text.ParagraphSpacing(10);
  326. foreach (var i in Enumerable.Range(1, 100))
  327. text.Line($"{i}: {Placeholders.Paragraph()}");
  328. });
  329. });
  330. }
  331. [Test]
  332. public void SpaceIssue()
  333. {
  334. RenderingTest
  335. .Create()
  336. .PageSize(PageSizes.A4)
  337. .ProducePdf()
  338. .ShowResults()
  339. .Render(container =>
  340. {
  341. container
  342. .Padding(20)
  343. .Padding(10)
  344. .MinimalBox()
  345. .Border(1)
  346. .Padding(5)
  347. .Padding(10)
  348. .Text(text =>
  349. {
  350. text.DefaultTextStyle(x => x.Bold());
  351. text.DefaultTextStyle(TextStyle.Default);
  352. text.AlignLeft();
  353. text.ParagraphSpacing(10);
  354. text.Span(Placeholders.LoremIpsum());
  355. text.EmptyLine();
  356. text.Span("This text is a normal text, ");
  357. text.Span("this is a bold text, ").Bold();
  358. text.Span("this is a red and underlined text, ").FontColor(Colors.Red.Medium).Underline();
  359. text.Span("and this is slightly bigger text.").FontSize(16);
  360. text.EmptyLine();
  361. text.Span("The new text element also supports injecting custom content between words: ");
  362. text.Element().PaddingBottom(-4).Height(16).Width(32).Image(Placeholders.Image);
  363. text.Span(".");
  364. text.EmptyLine();
  365. text.Span("This is page number ");
  366. text.CurrentPageNumber();
  367. text.Span(" out of ");
  368. text.TotalPages();
  369. text.EmptyLine();
  370. text.Hyperlink("Please visit QuestPDF website", "https://www.questpdf.com");
  371. text.EmptyLine();
  372. text.Span(Placeholders.Paragraphs());
  373. text.EmptyLine();
  374. text.Span(Placeholders.Paragraphs()).Italic();
  375. text.Line("This is target text that does not show up. " + Placeholders.Paragraph());
  376. });
  377. });
  378. }
  379. [Test]
  380. public void HugeList()
  381. {
  382. RenderingTest
  383. .Create()
  384. .PageSize(PageSizes.A4)
  385. .ProducePdf()
  386. .ShowResults()
  387. .Render(container =>
  388. {
  389. container
  390. .Padding(20)
  391. .Padding(10)
  392. .MinimalBox()
  393. .Border(1)
  394. .Padding(5)
  395. .Padding(10)
  396. .Text(text =>
  397. {
  398. text.DefaultTextStyle(TextStyle.Default.FontSize(20).BackgroundColor(Colors.Red.Lighten4));
  399. text.AlignLeft();
  400. text.ParagraphSpacing(10);
  401. text.Span("This text is a normal text, ");
  402. text.Span("this is a bold text, ").Bold();
  403. text.Span("this is a red and underlined text, ").FontColor(Colors.Red.Medium).Underline();
  404. text.Span("and this is slightly bigger text.").FontSize(16);
  405. text.Span("The new text element also supports injecting custom content between words: ");
  406. text.Element().PaddingBottom(-4).Height(16).Width(32).Image(Placeholders.Image);
  407. text.Span(".");
  408. text.EmptyLine();
  409. foreach (var i in Enumerable.Range(1, 100))
  410. {
  411. text.Line($"{i}: {Placeholders.Paragraph()}");
  412. text.Hyperlink("Please visit QuestPDF website. ", "https://www.questpdf.com");
  413. text.Span("This is page number ");
  414. text.CurrentPageNumber();
  415. text.Span(" out of ");
  416. text.TotalPages();
  417. text.EmptyLine();
  418. }
  419. });
  420. });
  421. }
  422. [Test]
  423. public void MeasureIssueWhenSpaceAtLineEnd()
  424. {
  425. // issue 135
  426. RenderingTest
  427. .Create()
  428. .ProduceImages()
  429. .ShowResults()
  430. .RenderDocument(container =>
  431. {
  432. container.Page(page =>
  433. {
  434. page.Margin(50);
  435. page.PageColor(Colors.White);
  436. page.Size(PageSizes.A4);
  437. page.Content().Text("This is a specially crafted sentence with a specially chosen length for demonstration of the bug that occurs ;;;;;. ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
  438. });
  439. });
  440. }
  441. [Test]
  442. public void EmptyText()
  443. {
  444. // issue 135
  445. RenderingTest
  446. .Create()
  447. .ProduceImages()
  448. .ShowResults()
  449. .RenderDocument(container =>
  450. {
  451. container.Page(page =>
  452. {
  453. page.Margin(50);
  454. page.PageColor(Colors.White);
  455. page.Size(PageSizes.A4);
  456. page.Content().Text(" ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
  457. });
  458. });
  459. }
  460. [Test]
  461. public void Whitespaces()
  462. {
  463. // issue 135
  464. RenderingTest
  465. .Create()
  466. .ProduceImages()
  467. .ShowResults()
  468. .RenderDocument(container =>
  469. {
  470. container.Page(page =>
  471. {
  472. page.Margin(50);
  473. page.PageColor(Colors.White);
  474. page.Size(PageSizes.A4);
  475. page.Content().Text(" x ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
  476. });
  477. });
  478. }
  479. [Test]
  480. public void DrawingNullTextShouldNotThrowException()
  481. {
  482. RenderingTest
  483. .Create()
  484. .ProduceImages()
  485. .ShowResults()
  486. .RenderDocument(container =>
  487. {
  488. container.Page(page =>
  489. {
  490. page.Margin(50);
  491. page.PageColor(Colors.White);
  492. page.Size(PageSizes.A4);
  493. page.Content().Column(column =>
  494. {
  495. column.Item().Text(null);
  496. column.Item().Text(text =>
  497. {
  498. text.Span(null);
  499. text.Line(null);
  500. text.Hyperlink(null, "http://www.questpdf.com");
  501. text.TotalPages().Format(x => null);
  502. });
  503. });
  504. });
  505. });
  506. }
  507. [Test]
  508. public void BreakingLongWord()
  509. {
  510. RenderingTest
  511. .Create()
  512. .ProduceImages()
  513. .ShowResults()
  514. .RenderDocument(container =>
  515. {
  516. container.Page(page =>
  517. {
  518. page.Margin(50);
  519. page.PageColor(Colors.White);
  520. page.Size(PageSizes.A4);
  521. page.Content().Column(column =>
  522. {
  523. column.Item().Text(null);
  524. column.Item().Text(text =>
  525. {
  526. text.DefaultTextStyle(x => x.BackgroundColor(Colors.Red.Lighten3).FontSize(24));
  527. text.Span(" " + Placeholders.LoremIpsum());
  528. text.Span(" 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 ").WrapAnywhere();
  529. });
  530. });
  531. });
  532. });
  533. }
  534. [Test]
  535. public void TextShaping_Unicode()
  536. {
  537. RenderingTest
  538. .Create()
  539. .PageSize(600, 100)
  540. .ProduceImages()
  541. .ShowResults()
  542. .Render(container =>
  543. {
  544. container
  545. .Padding(35)
  546. .MinimalBox()
  547. .Background(Colors.Grey.Lighten2)
  548. .Text(text =>
  549. {
  550. text.DefaultTextStyle(TextStyle.Default.FontSize(20));
  551. text.Span("Complex Unicode structure: ");
  552. text.Span("T̶̖̔͆͆̽̔ḩ̷̼̫̐̈́̀͜͝͝ì̶͇̤͓̱̣͇͓͉̎s̵̡̟̹͍̜͉̗̾͛̈̐́͋͂͝͠ͅ ̴̨͙͍͇̭̒͗̀́͝ì̷̡̺͉̼̏̏̉̌͝s̷͍͙̗̰̖͙̈̑̂̔͑͊̌̓̊̇͜ ̶̛̼͚͊̅͘ṭ̷̨̘̣̙̖͉͌̏̂̅͑̄̽̕͝ȅ̶̲̲̙̭͈̬̣͔̝͔̈́͝s̸̢̯̪̫͓̭̮̓̀͆͜ț̸̢͉̞̥̤̏̌̓͝").FontFamily(Fonts.Calibri).FontColor(Colors.Red.Medium);
  553. text.Span(".");
  554. });
  555. });
  556. }
  557. [Test]
  558. public void TextShaping_Arabic()
  559. {
  560. RenderingTest
  561. .Create()
  562. .PageSize(500, 100)
  563. .ProduceImages()
  564. .ShowResults()
  565. .Render(container =>
  566. {
  567. container
  568. .Padding(25)
  569. .MinimalBox()
  570. .Background(Colors.Grey.Lighten2)
  571. .Text("ينا الألم. في بعض الأحيان ونظراً للالتزامات التي يفرضها علينا")
  572. .FontFamily(Fonts.Calibri)
  573. .FontSize(20);
  574. });
  575. }
  576. [Test]
  577. public void FontFallback()
  578. {
  579. RenderingTest
  580. .Create()
  581. .ProduceImages()
  582. .ShowResults()
  583. .RenderDocument(container =>
  584. {
  585. container.Page(page =>
  586. {
  587. page.Margin(50);
  588. page.PageColor(Colors.White);
  589. page.DefaultTextStyle(x => x
  590. .Fallback(y => y.FontFamily("Segoe UI Emoji")
  591. .Fallback(y => y.FontFamily("Microsoft YaHei"))));
  592. page.Size(PageSizes.A4);
  593. page.Content().Text(t =>
  594. {
  595. t.Line("This is normal text.");
  596. t.EmptyLine();
  597. t.Line("Following line should use font fallback:");
  598. t.Line("中文文本");
  599. t.EmptyLine();
  600. t.Line("The following line contains a mix of known and unknown characters.");
  601. t.Line("Mixed line: This 中文 is 文文 a mixed 本 本 line 本 中文文本!");
  602. t.EmptyLine();
  603. t.Line("Emojis work out of the box because of font fallback: 😊😅🥳👍❤😍👌");
  604. });
  605. });
  606. });
  607. }
  608. [Test]
  609. public void WordWrappingStability()
  610. {
  611. // instruction: check if any characters repeat when performing the word-wrapping algorithm
  612. RenderingTest
  613. .Create()
  614. .PageSize(PageSizes.A4)
  615. .ProducePdf()
  616. .ShowResults()
  617. .Render(container =>
  618. {
  619. var text = "Lorem ipsum dolor sit amet consectetuer";
  620. container
  621. .Padding(20)
  622. .Column(column =>
  623. {
  624. column.Spacing(10);
  625. foreach (var width in Enumerable.Range(25, 200))
  626. {
  627. column
  628. .Item()
  629. .MaxWidth(width)
  630. .Background(Colors.Grey.Lighten3)
  631. .Text(text);
  632. }
  633. });
  634. });
  635. }
  636. }
  637. }