From 58f3932241263e661448baca26621c6e2a2c35e4 Mon Sep 17 00:00:00 2001 From: Collin Alpert Date: Mon, 3 Oct 2022 15:28:48 +0200 Subject: [PATCH 01/13] Update readme.md --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 94bd094..dda084e 100644 --- a/readme.md +++ b/readme.md @@ -69,7 +69,7 @@ dotnet add package QuestPDF ## Documentation -[![Getting started tutorial]( https://img.shields.io/badge/%F0%9F%9A%80%20read-getting%20started-blue)](https://www.questpdf.com/getting-started.html) +[![Getting started tutorial]( https://img.shields.io/badge/%F0%9F%9A%80%20read-getting%20started-blue)](https://www.questpdf.com/getting-started) A short and easy to follow tutorial showing how to design an invoice document under 200 lines of code. @@ -77,14 +77,14 @@ A short and easy to follow tutorial showing how to design an invoice document un A detailed description of behavior of all available components and how to use them with C# Fluent API. -[![Patterns and Practices](https://img.shields.io/badge/%E2%9C%A8%20read-patterns%20and%20practices-blue)](https://www.questpdf.com/design-patterns.html) +[![Patterns and Practices](https://img.shields.io/badge/%E2%9C%A8%20read-patterns%20and%20practices-blue)](https://www.questpdf.com/design-patterns) Everything that may help you designing great reports and create reusable code that is easy to maintain. ## QuestPDF Previewer The QuestPDF Previewer is a tool designed to simplify and speed up your development lifecycle. First, it shows a preview of your document. But the real magic starts with the hot-reload capability! It observes your code and updates the preview every time you change the implementation. Get real-time results without the need of code recompilation. Save time and enjoy the task! -[![Learn more](https://img.shields.io/badge/%F0%9F%93%96%20Previewer-learn%20more-blue)](https://www.questpdf.com/document-previewer.html) +[![Learn more](https://img.shields.io/badge/%F0%9F%93%96%20Previewer-learn%20more-blue)](https://www.questpdf.com/document-previewer) From 261f087b46aabc47c117d82c910d30971b6e327d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Tue, 4 Oct 2022 12:30:36 +0200 Subject: [PATCH 02/13] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index dda084e..64e0bf6 100644 --- a/readme.md +++ b/readme.md @@ -62,7 +62,7 @@ Install-Package QuestPDF dotnet add package QuestPDF // Package reference in .csproj file - + ``` [![Nuget version](https://img.shields.io/badge/package%20details-QuestPDF-blue?logo=nuget)](https://www.nuget.org/packages/QuestPDF/) From 16a164e5b8780974bf4317fba80b50c458ed6b1a Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Wed, 5 Oct 2022 01:15:30 +0200 Subject: [PATCH 03/13] Example: achieve proportional height division --- QuestPDF.Examples/RowExamples.cs | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/QuestPDF.Examples/RowExamples.cs b/QuestPDF.Examples/RowExamples.cs index cb01f78..57bdbe2 100644 --- a/QuestPDF.Examples/RowExamples.cs +++ b/QuestPDF.Examples/RowExamples.cs @@ -105,5 +105,41 @@ namespace QuestPDF.Examples .Row(row => { }); }); } + + [Test] + public void RowElementForRelativeHeightDivision() + { + RenderingTest + .Create() + .ProduceImages() + .ShowResults() + .MaxPages(100) + .PageSize(250, 400) + .Render(container => + { + container + .Padding(25) + .AlignLeft() + .RotateRight() + .Row(row => + { + row.Spacing(20); + + row.RelativeItem(1).Element(Content); + row.RelativeItem(2).Element(Content); + row.RelativeItem(3).Element(Content); + + void Content(IContainer container) + { + container + .RotateLeft() + .Border(1) + .Background(Placeholders.BackgroundColor()) + .Padding(5) + .Text(Placeholders.Label()); + } + }); + }); + } } } \ No newline at end of file From 20d86cbfded82a5b7643683a8cdf6d1d0980b5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Wed, 5 Oct 2022 22:49:03 +0200 Subject: [PATCH 04/13] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 64e0bf6..5dda010 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ It offers a layouting engine designed with a full paging support in mind. The do Unlike other libraries, it does not rely on the HTML-to-PDF conversion which in many cases is not reliable. Instead, it implements its own layouting engine that is optimized to cover all paging-related requirements. -## Please show the value +## Please help by giving a star Choosing a project dependency could be difficult. We need to ensure stability and maintainability of our projects. Surveys show that GitHub stars count play an important factor when assessing library quality. From 6c8867e1b31cb08e4f9bc3588e0d4e7ba385ff68 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Thu, 6 Oct 2022 23:20:12 +0200 Subject: [PATCH 05/13] Added test: ReusingTheSameImageFileShouldBePossible --- QuestPDF.Examples/ImageExamples.cs | 41 +++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/QuestPDF.Examples/ImageExamples.cs b/QuestPDF.Examples/ImageExamples.cs index b3bed24..74cc4cf 100644 --- a/QuestPDF.Examples/ImageExamples.cs +++ b/QuestPDF.Examples/ImageExamples.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using NUnit.Framework; using QuestPDF.Drawing.Exceptions; using QuestPDF.Examples.Engine; @@ -47,5 +48,43 @@ namespace QuestPDF.Examples .Render(page => page.Image("non_existent.png")); }); } + + [Test] + public void ReusingTheSameImageFileShouldBePossible() + { + var fileName = Path.GetTempFileName() + ".jpg"; + + try + { + var image = Placeholders.Image(300, 100); + + using var file = File.Create(fileName); + file.Write(image); + file.Dispose(); + + RenderingTest + .Create() + .ProducePdf() + .PageSize(PageSizes.A4) + .ShowResults() + .Render(container => + { + container + .Padding(20) + .Column(column => + { + column.Spacing(20); + + column.Item().Image(fileName); + column.Item().Image(fileName); + column.Item().Image(fileName); + }); + }); + } + finally + { + File.Delete(fileName); + } + } } } \ No newline at end of file From ec31c9b063593a07fccd9690faceaccd2b8dceba Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Tue, 11 Oct 2022 10:31:31 +0200 Subject: [PATCH 06/13] Fix: CheckIfAllTextGlyphsAreAvailable and Fallback break hyperlinks --- QuestPDF/Elements/Text/FontFallback.cs | 22 ++++++++++++++----- QuestPDF/Elements/Text/Items/TextBlockSpan.cs | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/QuestPDF/Elements/Text/FontFallback.cs b/QuestPDF/Elements/Text/FontFallback.cs index 5eabe9c..cb215d4 100644 --- a/QuestPDF/Elements/Text/FontFallback.cs +++ b/QuestPDF/Elements/Text/FontFallback.cs @@ -121,7 +121,11 @@ namespace QuestPDF.Elements.Text { foreach (var textBlockItem in textBlockItems) { - if (textBlockItem is TextBlockSpan textBlockSpan and not TextBlockPageNumber) + if (textBlockItem is TextBlockPageNumber or TextBlockElement) + { + yield return textBlockItem; + } + else if (textBlockItem is TextBlockSpan textBlockSpan) { if (!Settings.CheckIfAllTextGlyphsAreAvailable && textBlockSpan.Style.Fallback == null) { @@ -130,19 +134,25 @@ namespace QuestPDF.Elements.Text } var textRuns = textBlockSpan.Text.SplitWithFontFallback(textBlockSpan.Style); - + foreach (var textRun in textRuns) { - yield return new TextBlockSpan + var newElement = textBlockSpan switch { - Text = textRun.Content, - Style = textRun.Style + TextBlockHyperlink hyperlink => new TextBlockHyperlink { Url = hyperlink.Url }, + TextBlockSectionLink sectionLink => new TextBlockSectionLink { SectionName = sectionLink.SectionName }, + TextBlockSpan => new TextBlockSpan() }; + + newElement.Text = textRun.Content; + newElement.Style = textRun.Style; + + yield return newElement; } } else { - yield return textBlockItem; + throw new NotSupportedException(); } } } diff --git a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs index 4dfad0f..459acc3 100644 --- a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs +++ b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs @@ -15,7 +15,7 @@ namespace QuestPDF.Elements.Text.Items { public string Text { get; set; } public TextStyle Style { get; set; } = TextStyle.Default; - public TextShapingResult? TextShapingResult { get; set; } + private TextShapingResult? TextShapingResult { get; set; } private Dictionary<(int startIndex, float availableWidth), TextMeasurementResult?> MeasureCache = new (); protected virtual bool EnableTextCache => true; From 680142508289a66a1cd64d7bb12aab7f9bc63c0d Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Tue, 11 Oct 2022 22:39:31 +0200 Subject: [PATCH 07/13] Fix: cells with RowSpan are not always displayed properly #320 --- QuestPDF/Elements/Table/Table.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/QuestPDF/Elements/Table/Table.cs b/QuestPDF/Elements/Table/Table.cs index 6663f50..00322a7 100644 --- a/QuestPDF/Elements/Table/Table.cs +++ b/QuestPDF/Elements/Table/Table.cs @@ -202,7 +202,7 @@ namespace QuestPDF.Elements.Table // cell visibility optimizations if (cell.Row > maxRenderingRow) - break; + continue; // calculate cell position / size var topOffset = rowBottomOffsets[cell.Row - 1]; @@ -218,14 +218,14 @@ namespace QuestPDF.Elements.Table { maxRenderingRow = Math.Min(maxRenderingRow, cell.Row + cell.RowSpan - 1); } - + // corner case: if cell within the row want to wrap to the next page, do not attempt to render this row if (cellSize.Type == SpacePlanType.Wrap) { maxRenderingRow = Math.Min(maxRenderingRow, cell.Row - 1); continue; } - + // update position of the last row that cell occupies var bottomRow = cell.Row + cell.RowSpan - 1; rowBottomOffsets[bottomRow] = Math.Max(rowBottomOffsets[bottomRow], topOffset + cellSize.Height); From e1f7cff4aaf75f3e5e4403970565e0cf7eba5465 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Tue, 11 Oct 2022 23:19:13 +0200 Subject: [PATCH 08/13] Fix: performance regression of the Table element #320 --- QuestPDF/Elements/Table/Table.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/QuestPDF/Elements/Table/Table.cs b/QuestPDF/Elements/Table/Table.cs index 00322a7..12d188c 100644 --- a/QuestPDF/Elements/Table/Table.cs +++ b/QuestPDF/Elements/Table/Table.cs @@ -24,6 +24,7 @@ namespace QuestPDF.Elements.Table // inner table: list of all cells that ends at the corresponding row private TableCell[][] CellsCache { get; set; } private int MaxRow { get; set; } + private int MaxRowSpan { get; set; } internal override void Initialize(IPageContext pageContext, ICanvas canvas) { @@ -56,6 +57,7 @@ namespace QuestPDF.Elements.Table if (Cells.Count == 0) { MaxRow = 0; + MaxRowSpan = 1; CellsCache = Array.Empty(); return; @@ -66,6 +68,7 @@ namespace QuestPDF.Elements.Table .ToDictionary(x => x.Key, x => x.OrderBy(x => x.Column).ToArray()); MaxRow = groups.Max(x => x.Key); + MaxRowSpan = Cells.Max(x => x.RowSpan); CellsCache = Enumerable .Range(0, MaxRow + 1) @@ -199,10 +202,10 @@ namespace QuestPDF.Elements.Table currentRow = cell.Row; } - + // cell visibility optimizations - if (cell.Row > maxRenderingRow) - continue; + if (cell.Row > maxRenderingRow + MaxRowSpan) + break; // calculate cell position / size var topOffset = rowBottomOffsets[cell.Row - 1]; From 389b8ce304547c8e69440917d09ad40f0f1f0171 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Sat, 15 Oct 2022 22:49:50 +0200 Subject: [PATCH 09/13] Inlined: improved behaviour predictability --- QuestPDF/Elements/Inlined.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuestPDF/Elements/Inlined.cs b/QuestPDF/Elements/Inlined.cs index f2164c7..36ed250 100644 --- a/QuestPDF/Elements/Inlined.cs +++ b/QuestPDF/Elements/Inlined.cs @@ -212,7 +212,7 @@ namespace QuestPDF.Elements break; var element = queue.Peek(); - var size = element.Measure(Size.Max); + var size = element.Measure(new Size(availableSize.Width, Size.Max.Height)); if (size.Type == SpacePlanType.Wrap) break; From 8214a8429d835fcdee75f6aec75ac7cfba77bffc Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Sat, 15 Oct 2022 23:03:25 +0200 Subject: [PATCH 10/13] 2022.9.1 --- QuestPDF/QuestPDF.csproj | 2 +- QuestPDF/Resources/ReleaseNotes.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/QuestPDF/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj index c581f5e..503d9b7 100644 --- a/QuestPDF/QuestPDF.csproj +++ b/QuestPDF/QuestPDF.csproj @@ -3,7 +3,7 @@ MarcinZiabek CodeFlint QuestPDF - 2022.9.0 + 2022.9.1 QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API. $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt")) 9 diff --git a/QuestPDF/Resources/ReleaseNotes.txt b/QuestPDF/Resources/ReleaseNotes.txt index 44c7fc7..c9e13c1 100644 --- a/QuestPDF/Resources/ReleaseNotes.txt +++ b/QuestPDF/Resources/ReleaseNotes.txt @@ -4,3 +4,8 @@ - Significantly reduced memory allocation cost for TextStyle objects, - Implemented optional checking if all font glyphs are available, - Minor text-rendering optimizations. + +2022.9.1 +- Fixed: text hyperlinks do not work when the CheckIfAllTextGlyphsAreAvailable option or text fallback are used, +- Fixed: cells with RowSpan (greater than 1) are not always displayed properly, +- Improved predictability of the Inlined element when measuring its children. \ No newline at end of file From 5cbacc7ea1c6e01039c919c7967ab2b8a94381ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Wed, 19 Oct 2022 19:15:25 +0200 Subject: [PATCH 11/13] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 5dda010..7c3cd3f 100644 --- a/readme.md +++ b/readme.md @@ -47,6 +47,7 @@ Special thanks to all companies that decided to sponsor QuestPDF development. Th | Company | Description | |--------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------| | | [JetBrains](https://www.jetbrains.com/) supports this project as part of the OSS Power-Ups program. Thank you!
100$ / month | +| | [Mark Gould](https://github.com/markgould) supports this project. Thank you!
100$ / month | [![Sponsor project](https://img.shields.io/badge/%E2%9D%A4%EF%B8%8F%20sponsor-QuestPDF-red)](https://github.com/sponsors/QuestPDF) From 9d86e9efd36f23a857833bc72067d520457014fe Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Wed, 19 Oct 2022 20:08:35 +0200 Subject: [PATCH 12/13] DynamicImage: simplified implementation --- QuestPDF.Examples/ImageExamples.cs | 15 +++++++++++++++ QuestPDF/Elements/DynamicImage.cs | 9 ++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/QuestPDF.Examples/ImageExamples.cs b/QuestPDF.Examples/ImageExamples.cs index 74cc4cf..91bf3af 100644 --- a/QuestPDF.Examples/ImageExamples.cs +++ b/QuestPDF.Examples/ImageExamples.cs @@ -35,6 +35,21 @@ namespace QuestPDF.Examples }); } + [Test] + public void DynamicImage() + { + RenderingTest + .Create() + .PageSize(450, 350) + .ProducePdf() + .ShowResults() + .Render(page => + { + page.Padding(25) + .Image(Placeholders.Image); + }); + } + [Test] public void Exception() { diff --git a/QuestPDF/Elements/DynamicImage.cs b/QuestPDF/Elements/DynamicImage.cs index 514fe16..e3ac262 100644 --- a/QuestPDF/Elements/DynamicImage.cs +++ b/QuestPDF/Elements/DynamicImage.cs @@ -24,13 +24,8 @@ namespace QuestPDF.Elements if (imageData == null) return; - var imageElement = new Image - { - InternalImage = SKImage.FromEncodedData(imageData) - }; - - imageElement.Initialize(PageContext, Canvas); - imageElement.Draw(availableSpace); + using var image = SKImage.FromEncodedData(imageData); + Canvas.DrawImage(image, Position.Zero, availableSpace); } } } \ No newline at end of file From 65990ebf59037d172379f6a3491430daa4aabffc Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Fri, 21 Oct 2022 12:05:45 +0200 Subject: [PATCH 13/13] Added the WordWrappingStability test --- QuestPDF.Examples/TextExamples.cs | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/QuestPDF.Examples/TextExamples.cs b/QuestPDF.Examples/TextExamples.cs index 905bcb8..a3c0c12 100644 --- a/QuestPDF.Examples/TextExamples.cs +++ b/QuestPDF.Examples/TextExamples.cs @@ -657,5 +657,37 @@ namespace QuestPDF.Examples }); }); } + + [Test] + public void WordWrappingStability() + { + // instruction: check if any characters repeat when performing the word-wrapping algorithm + + RenderingTest + .Create() + .PageSize(PageSizes.A4) + .ProducePdf() + .ShowResults() + .Render(container => + { + var text = "Lorem ipsum dolor sit amet consectetuer"; + + container + .Padding(20) + .Column(column => + { + column.Spacing(10); + + foreach (var width in Enumerable.Range(25, 200)) + { + column + .Item() + .MaxWidth(width) + .Background(Colors.Grey.Lighten3) + .Text(text); + } + }); + }); + } } } \ No newline at end of file