QuestPDF is a modern open-source .NET library for PDF document generation. Offering comprehensive layout engine powered by concise and discoverable C# Fluent API. Easily generate PDF reports, invoices, exports, etc.
OTHER License
Bot releases are visible (Hide)
Published by MarcinZiabek 12 months ago
Version 2023.10.1
Published by MarcinZiabek 12 months ago
Let's analyse a simple example showing how the new layout issue debugging mechanism works in practice. In the following scenario, we are artifically limiting the available vertical space, which makes the text content overflow:
container
.ShowEntire()
.Background(Colors.Grey.Lighten3)
.Padding(10)
.MaxHeight(20) // <- here is the problematic element
.Column(column =>
{
column.Spacing(5);
column.Item().Text("Comments").FontSize(14).SemiBold();
column.Item().Text(Model.Comments);
});
This results in the following output when generating the document with the debugger attached. The green area represents available space, while the red area shows the overflow.
Published by MarcinZiabek about 1 year ago
Published by MarcinZiabek about 1 year ago
Row
element respects now available vertical space, which is closer to expected behaviorPublished by MarcinZiabek about 1 year ago
Fix: the GeneratePdfAndShow
method does not always properly open the generated PDF file in a default application due to a timing issue.
Published by MarcinZiabek about 1 year ago
Image.FitUnproportionally
behavior to ensure it now respects minimal size constraints and doesn't just expand to use all the available space.Published by MarcinZiabek over 1 year ago
Version 2023.6.0
Published by MarcinZiabek over 1 year ago
Version 2023.5.0
Version 2023.5.1
Published by MarcinZiabek over 1 year ago
This release does not contain any features or quality improvements.
Its purpose is to mark the QuestPDF shift towards the dual-licensing model.
Most users are not affected by this change.
Please visit the https://www.questpdf.com/pricing.html webpage for more information.
Added IntelliSense-powered documentation for certain API methods.
Fix: fixed the rendering order of table cells in certain scenarios
Published by MarcinZiabek over 1 year ago
Feature: implemented LetterSpacing property for the Text element
Improvement: the Text element API now accepts only string values; objects are not automatically converted anymore
Fix: the Alignment element incorrectly limits the size of its child when only one axis is set (horizontal or vertical)
Maintenance: Updated SkiaSharp dependency to 2.88.3
This release was possible thanks to the enormous help of AntonyCorbett. Thank you!
Fixed: loading fonts from embedded resource via the FontManager.RegisterFontFromEmbeddedResource method
Fixed: better layout calculation stability for the Column element
Improvement: exposed missing API method for the Dynamic component, enabling applying more advanced optimizations
Improvement: better API documentation for the Settings.DocumentLayoutExceptionThreshold property
Performance improvements in various areas
Text rendering stability improvements
Fixed: the Settings.CheckIfAllTextGlyphsAreAvailable setting does not work correctly
Fix: inconsistent text height when using multiple lines with different TextStyles
Improvement: added validation for color arguments
Fix: the inlined element is shown only once in the header but should be repeated on each page
Fix: the TextStyle.Fallback property incorrectly inherits parent's and global properties
Improvement: updated the CreateNotMatchingFontException message to mention that the glyph checking operation can be disabled with the Settings.CheckIfAllTextGlyphsAreAvailable setting
Fixed release regression
Fix: fixed the rendering order of table cells in certain scenarios
Published by MarcinZiabek almost 2 years ago
QuestPDF offers a layout engine designed with full paging support in mind. The document consists of many simple elements (e.g. border, background, image, text, padding, table, grid etc.) that are composed together to create more complex structures. This way, as a developer, you can understand the behavior of every element and use them with full confidence. Additionally, the document and all its elements support paging functionality. For example, an element can be moved to the next page (if there is not enough space) or even be split between pages like table's rows.
To learn how easy it is to design documents with the library, let's quickly analyse the code below:
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// code in your main method
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(20));
page.Header()
.Text("Hello PDF!")
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(x =>
{
x.Spacing(20);
x.Item().Text(Placeholders.LoremIpsum());
x.Item().Image(Placeholders.Image(200, 100));
});
page.Footer()
.AlignCenter()
.Text(x =>
{
x.Span("Page ");
x.CurrentPageNumber();
});
});
})
.GeneratePdf("hello.pdf");
And compare it to the produced PDF file:
⭐ Please consider giving a start to this repository. It takes seconds and helps thousands of developers! ⭐
This QuestPDF release is special as it mainly consists of features proposed and developed by the community:
Feature: implemented LetterSpacing property for the Text element (implemeneted by @Bebo-Maker in #398)
Improvement: the Text element API accepts now only string values, objects are not automatically converted anymore (proposed by @rstm-sf in #362)
Fix: the Alignment element incorrectly limits size of its child when only one axis is set: horizontal or vertical (found by @zlatanov in #401)
Maintenance: Updated SkiaSharp dependency to 2.88.3. Updated Avalonia dependency in the QuestPDF.Previewer project to the latest version. (this was a long awaiting effort that should improve experience for many developers)
Development: Implemented usage on GitHub Actions to trigger automated solution build after every commit. This build is also used for packing nuget artifacts. It is a great starting point for future improvements. (proposed by @rstm-sf in #366)
Let me thank you all for your help!
Letter spacing allows to increase or decrease space between characters. This setting is useful when you want to make the text more compact (by decreasing letter spacing) or easier to read (by increasing letter spacing):
This settings uses relative units. Example: let's assume your text has font size 20. If letter spacing is set to 0.1, an additional space of 2 points will be added between characters.
.Column(column =>
{
var letterSpacing = new[] { -0.05f, 0f, 0.2f };
var paragraph = Placeholders.Sentence();
foreach (var spacing in letterSpacing)
{
column
.Item()
.Border(1)
.Padding(10)
.Column(nestedColumn =>
{
nestedColumn
.Item()
.Text(paragraph)
.FontSize(18)
.LetterSpacing(spacing); // <- here 😊
nestedColumn
.Item()
.Text($"Letter spacing of {spacing} em")
.FontSize(14)
.Italic()
.FontColor(Colors.Blue.Medium);
});
}
});
Published by MarcinZiabek almost 2 years ago
QuestPDF offers a layout engine designed with full paging support in mind. The document consists of many simple elements (e.g. border, background, image, text, padding, table, grid etc.) that are composed together to create more complex structures. This way, as a developer, you can understand the behavior of every element and use them with full confidence. Additionally, the document and all its elements support paging functionality. For example, an element can be moved to the next page (if there is not enough space) or even be split between pages like table's rows.
To learn how easy it is to design documents with the library, let's quickly analyse the code below:
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// code in your main method
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(20));
page.Header()
.Text("Hello PDF!")
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(x =>
{
x.Spacing(20);
x.Item().Text(Placeholders.LoremIpsum());
x.Item().Image(Placeholders.Image(200, 100));
});
page.Footer()
.AlignCenter()
.Text(x =>
{
x.Span("Page ");
x.CurrentPageNumber();
});
});
})
.GeneratePdf("hello.pdf");
And compare it to the produced PDF file:
Two major releases ago, I was excited to mention that QuestPDF has over 250 thousand downloads. Very little did I know that the next milestone will come so quickly! Three months have passed and now we are in the middle of to-the-million journey. Maybe somewhere in 2023? Something that was a dream, now sounds plausible. Thank you all for helping me in this process!
⭐ Please consider giving a start to this repository. It takes seconds and helps thousands of developers! ⭐
Most languages (such as English, German, Polish, etc.) are using the left-to-right content direction. However, there are languages (e.g. Arabic) that use the right-to-left content direction.
The right-to-left content direction significantly changes how the layout is planned:
The new content-direction API introduces the possibility to set this feature locally to entire child content, or even override this setting:
.ContentFromRightToLeft()
.Column(column =>
{
// this content uses inherited right-to-left content direction
column.Item() // ... content
// this item overrides the content direction to right-to-left
column.Item().ContentFromLeftToRight() // ... content
});
The RTL mode is supported in all available elements. Let's quickly analyse a couple of examples to learn on how this mode infers the rendering process. In the Row element, the elements are displayed in accordance to the content direction. For example, the first element is put most to the left (in LTR mode) or most to the right (int RTL) mode:
.ContentFromRightToLeft() // LTR or RTL mode
.Row(row =>
{
row.Spacing(5);
row.AutoItem().Height(50).Width(50).Background(Colors.Red.Lighten1);
row.AutoItem().Height(50).Width(50).Background(Colors.Green.Lighten1);
row.AutoItem().Height(50).Width(75).Background(Colors.Blue.Lighten1);
});
It is important to notice that content direction does NOT impact element alignment. This is nicely shown when working with more advanced elements such as Inlined
:
It is also possible to set a global content direction for the entire document. Of course, it is still possible to override content direction locally using one of the above methods. Or even to apply conditional content direction.
Let's analyse a simple example showing an invoice generated with Arabic language.
document.Page(page =>
{
page.Size(PageSizes.A5);
page.Margin(20);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontFamily("Calibri").FontSize(20));
page.ContentFromRightToLeft(); // this flag changes content direction to RTL in entire document
page.Content().Column(column =>
{
column.Spacing(20);
column.Item()
.Text("مثال على الفاتورة") // example invoice
.FontSize(32).FontColor(Colors.Blue.Darken2).SemiBold();
column.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn();
columns.ConstantColumn(75);
columns.ConstantColumn(100);
});
table.Cell().Element(HeaderStyle).Text("وصف السلعة"); // item description
table.Cell().Element(HeaderStyle).Text("كمية"); // quantity
table.Cell().Element(HeaderStyle).Text("سعر"); // price
var items = new[]
{
"دورة البرمجة", // programming course
"دورة تصميم الرسومات", // graphics design course
"تحليل وتصميم الخوارزميات", // analysis and design of algorithms
};
foreach (var item in items)
{
var price = Placeholders.Random.NextDouble() * 100;
table.Cell().Text(item);
table.Cell().Text(Placeholders.Random.Next(1, 10));
table.Cell().Text($"USD${price:F2}");
}
static IContainer HeaderStyle(IContainer x) => x.BorderBottom(1).PaddingVertical(5);
});
});
});
Previous versions of QuestPDF have introduced an advanced text shaping support. This allows to properly render text of more advanced languages, where characters in words are often combined together and displayed as single glyphs.
This release fixes the word-wrapping algorithm. This example renders the same text but the available width changes in each block:
var text = "في المعلوماتية أو الرياضيات، خوارزمية الترتيب هي خوارزمية تمكن من تنظيم مجموعة عناصر حسب ترتيب محدد.";
container
.Padding(25)
.ContentFromRightToLeft()
.Column(column =>
{
column.Spacing(20);
foreach (var size in new[] { 36, 34, 32, 30, 15 })
{
column
.Item()
.ShowEntire()
.MaxWidth(size * 25)
.Background(Colors.Grey.Lighten3)
.MinimalBox()
.Background(Colors.Grey.Lighten2)
.Text(text)
.FontSize(20)
.FontFamily("Segoe UI");
}
});
QuestPDF automatically detects text direction and applies proper text alignment. However, it is possible to override text direction.
TextStyle.Default.DirectionAuto() // default
TextStyle.Default.DirectionFromLeftToRight()
TextStyle.Default.DirectionFromRightToLeft()
This may be useful with more advanced corner cases:
.DefaultTextStyle(x => x.FontSize(24).FontFamily("Calibri"))
.Column(column =>
{
var word = "الجوريتم";
var definition = "algorithm in Arabic";
var text = $"{word} - {definition}";
// text direction is automatically detected using the first word
column.Item().Text(text);
// it is possible to force specific content direction
column.Item().Text(text).DirectionFromLeftToRight();
column.Item().Text(text).DirectionFromRightToLeft();
// to combine text in various content directions, split it into segments
column.Item().Text(text =>
{
text.Span(word);
text.Span(" - ");
text.Span(definition);
});
});
Published by MarcinZiabek about 2 years ago
QuestPDF is an open-source .NET library for PDF documents generation.
It offers a layout engine designed with full paging support in mind. The document consists of many simple elements (e.g. border, background, image, text, padding, table, grid etc.) that are composed together to create more complex structures. This way, as a developer, you can understand the behavior of every element and use them with full confidence. Additionally, the document and all its elements support paging functionality. For example, an element can be moved to the next page (if there is not enough space) or even be split between pages like table's rows.
To learn how easy it is to design documents with the library, let's quickly analyse the code below:
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// code in your main method
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(20));
page.Header()
.Text("Hello PDF!")
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(x =>
{
x.Spacing(20);
x.Item().Text(Placeholders.LoremIpsum());
x.Item().Image(Placeholders.Image(200, 100));
});
page.Footer()
.AlignCenter()
.Text(x =>
{
x.Span("Page ");
x.CurrentPageNumber();
});
});
})
.GeneratePdf("hello.pdf");
And compare it to the produced PDF file:
The QuestPDF nuget package has reached over 250 thousands of downloads! I was dreaming about helping the community for years, about giving something back and be a part of the ecosystem development. This is not simple: requires tons of time and proper planning. But numbers are not lying! My hard work is beneficial to many of you. Thank you for your support!
⭐ Please consider giving this repository a star. It takes seconds and help thousands of developers! ⭐
🔣 Implemented font-fallback algorithm
⚙️ Introduced new Settings API,
🚀 Improved rendering performance by 50% (in text-heavy documents),
📉 Significantly reduced memory allocation cost for TextStyle objects,
🔎 Implemented optional checking if all font glyphs are available,
📉 Minor text-rendering optimizations.
During document generation, thousands of similar/identical TextStyles are generated. This increases GC overhead.
The cost of TextStyle objects became negligable:
There are several parameters used to alter document generation process. In the current implementation, such parameters are specified per document in the DocumentMetadata
object, like so:
public class DocumentMetadata
{
// actual metadata or rendering settings
// generation settings:
public int DocumentLayoutExceptionThreshold { get; set; } = 250;
public bool ApplyCaching { get; set; } // false when debugger is attached
public bool ApplyDebugging { get; set; } // true when debugger is attached
}
It becomes clear that with new library iterations, more and more parameters will be created. It is important to put them in the more meaningful place.
There are several parameters that alter the generation process. All of them are available under statically available Settings
class.
// settings definition with default settings
public static class Settings
{
public static int DocumentLayoutExceptionThreshold { get; set; } = 250;
public static bool EnableCaching { get; set; } = !System.Diagnostics.Debugger.IsAttached;
public static bool EnableDebugging { get; set; } = System.Diagnostics.Debugger.IsAttached;
public static bool CheckIfAllTextGlyphsAreAvailable { get; set; } = System.Diagnostics.Debugger.IsAttached;
}
// adjust properties wherever you want
// best in the startup code
QuestPDF.Settings.DocumentLayoutExceptionThreshold = 1000;
This value represents the maximum length of the document that the library produces. This is useful when layout constraints are too strong, e.g. one element does not fit in another. In such cases, the library would produce document of infinite length, consuming all available resources. To break the algorithm and save the environment, the library breaks the rendering process after reaching specified length of document.
If your content requires generating longer documents, please assign the most reasonable value.
QuestPDF.Settings.DocumentLayoutExceptionThreshold = 250;
This flag generates additional document elements to cache layout calculation results. In the vast majority of cases, this significantly improves performance, while slightly increasing memory consumption.
By default, this flag is enabled only when the debugger is NOT attached.
QuestPDF.Settings.EnableCaching = true;
This flag generates additional document elements to improve layout debugging experience. When the DocumentLayoutException is thrown, the library is able to provide additional execution context. It includes layout calculation results and path to the problematic area.
By default, this flag is enabled only when the debugger IS attached.
QuestPDF.Settings.EnableDebugging = false;
This flag enables checking the font glyph availability.
If your text contains glyphs that are not present in the specified font:
Enabling this flag may slightly decrease document generation performance. However, it provides hints that used fonts are not sufficient to produce correct results.
By default, this flag is enabled only when the debugger IS attached.
QuestPDF.Settings.CheckIfAllTextGlyphsAreAvailable = false;
Implementation of this feature has been started by @Bebo-Maker in #187. Thank you for your work and preparing this fantastic foundation. You really saved me a lot of time!
Each font file contains a well-specified set of glyphs. Sometimes, to reduce font file size, more advanced glyphs are not present. For example, English uses around a hundred of characters, whereas Chinesee requires thousands of glyphs. Therefore, it is possible that text in document may contain glyphs not available in the configured font. In such cases, an ugly character (usually square with question mark) is rendered.
The TextStyle object should allow to set a fallback TextStyle.
Algorithm:
It is possible to define font fallbacks like so:
TextStyle
.Default
.FontFamily(Fonts.Calibri)
.Fallback(x => x.FontFamily("Segoe UI Emoji")); // <- here
// or
TextStyle
.Default
.FontFamily(Fonts.Calibri)
.Fallback(TextStyle.Default.FontFamily("Segoe UI Emoji")); // <- and here
Let's analyse more complex example by defining text style supporting emojis and Chinesee glyphs.
var textStyleWithFallback = TextStyle
.Default
.FontFamily(Fonts.Calibri)
.FontSize(18)
.Fallback(x => x
.FontFamily("Segoe UI Emoji")
.NormalWeight()
.Underline()
.Fallback(y => y
.FontFamily("Microsoft YaHei")
.SemiBold()
.Underline(false)
.BackgroundColor(Colors.Red.Lighten4)));
And now, we can use the newly created style:
.Text(text =>
{
text.DefaultTextStyle(textStyleWithFallback);
text.Line("This is normal text.");
text.EmptyLine();
text.Line("Following line should use font fallback:");
text.Line("中文文本");
text.EmptyLine();
text.Line("The following line contains a mix of known and unknown characters.");
text.Line("Mixed line: This 中文 is 文文 a mixed 本 本 line 本 中文文本!");
text.EmptyLine();
text.Span("Emojis work out of the box because of font fallback: 😊😅🥳👍❤😍👌");
});
Please notice that additional styles (e.g. red background color) are applied only to glyphs from the associated fallback configuration. This let's you fine tune text parameters, e.g. to match visual text size in various fonts.
Before | After |
---|---|
The font-fallback implementation is opt-in. That means, it attempts to find best font based on the explicitly defined configuration. For stability and predictability reasons, it does not search through fonts available on the runtime environment.
Reason: quite often, development environment contains hundreds of fonts, whereas production environments contain very little to none. Relying on configuration makes sure that results produced on both environments are consistent.
When not all glyphs are present, even with configured fallbacks, the library should throw an exception. Additionally, the library can search through available fonts and propose list of fonts with desired glyph. Example exception:
QuestPDF.Drawing.Exceptions.DocumentDrawingException:
Could not find an appropriate font fallback for glyph: U-4E2D '中'.
Font families available on current environment that contain this glyph: Malgun Gothic, Microsoft JhengHei, Microsoft JhengHei UI, Microsoft YaHei, Microsoft YaHei UI, MS Gothic, MS UI Gothic, MS PGothic, SimSun, NSimSun, Yu Gothic, Yu Gothic UI, Droid Sans Fallback, MotoyaLCedar W3 mono.
Possible solutions:
1) Use one of the listed fonts as the primary font in your document.
2) Configure the fallback TextStyle using the 'TextStyle.Fallback' method with one of the listed fonts.
When this feature is disabled: do nothing, render placeholder glyphs (rectangle with question mark).
This feature depends on the current environment. The default configuration is as follows:
This behaviour can be changed by using the new settings API:
QuestPDF.Settings.CheckIfAllTextGlyphsAreAvailable = false;
In a typical document:
The Fluent API for text capability, produces additional hierarchy elements that are usually not needed:
DefaultTextStyle
element to apply global style, even if not specified.Column
to handle multiple paragraphs.Do not apply hierarchy elements if they are not needed.
Published by MarcinZiabek about 2 years ago
For all major changes introduced in the 2022.8 release, please read this article
Published by MarcinZiabek about 2 years ago
QuestPDF is an open-source .NET library for PDF documents generation.
It offers a layouting engine designed with a full paging support in mind. The document consists of many simple elements (e.g. border, background, image, text, padding, table, grid etc.) that are composed together to create more complex structures. This way, as a developer, you can understand the behavior of every element and use them with full confidence. Additionally, the document and all its elements support paging functionality. For example, an element can be moved to the next page (if there is not enough space) or even be split between pages like table's rows.
To learn how easy it is to design documents with the library, let's quickly analyse the code below:
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// code in your main method
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(20));
page.Header()
.Text("Hello PDF!")
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(x =>
{
x.Spacing(20);
x.Item().Text(Placeholders.LoremIpsum());
x.Item().Image(Placeholders.Image(200, 100));
});
page.Footer()
.AlignCenter()
.Text(x =>
{
x.Span("Page ");
x.CurrentPageNumber();
});
});
})
.GeneratePdf("hello.pdf");
And compare it to the produced PDF file:
The QuestPDF nuget package has reached over 250 thousands of downloads! I was dreaming about helping the community for years, about giving something back and be a part of the ecosystem development. This is not simple: requires tons of time and proper planning. But numbers are not lying! My hard work is beneficial to many of you. Thank you for your support!
⭐ Please consider giving this repository a star. It takes seconds and help thousands of developers! ⭐
The QuestPDF project received an enormous help from JetBrains over last months.
The library was shown during one of episodes of the OSS Power-Ups program hosted by Matthias Koch. This gave me a fresh energy to develop new great features.
Moreover, I got a change to cooperate with Maarten Balliauw, perform a detailed performance analysis and apply multiple fixes. To read more about this effort, please take a look at this fantastic article. Many of the improvements are already applied, making the library faster and more reliable for everyone. Some are inspiration for more fundamental changes that should significantly reduce resource utilization in the nearest future.
Dear JetBrains team, thank you for helping me making the library flourish, for promoting it across entire the .NET community, for your great patience and professionalism, and finally for making our industry a fantastic place to work.
The QuestPDF documentation is written manually as MarkDown files. Those files are then compiled together to create a webpage.
I decided to change the documentation engine from VuePress to VitePress. This makes the webpage much faster, improves its look and feel, as well as increases usability.
Also, the old documentation structure has been designed nearly two years ago. Since then, the documentation grew over three times in size. Therefore, I have also decided to update its hierarchy, so it should be easier to traverse and find what you need.
The next step is to rewrite all articles, make descriptions more accurate and provide more examples.
In this release, I decided to change the default font from Calibri
to Lato
. Lato is an open-source, free for commercial use font created by Polish author Łukasz Dziedzic.
The font is distributed with the library as embedded resource and part of the dll file / nuget package. This way, as long as you use the default font, you have it available on all environments. Also, the font is around 20x smaller, this should reduce substantially PDF file size (1.57 MB -> 74 KB) when using the default font.
Of course there is caveat, this font does not contain more advanced glyphs, e.g. for Arabic/Chinese/Japanese languages, or for advanced unicode formatting. For such cases, you still need to use a font with proper support.
This effort solves two issues:
Improved: if you use the font that is not available in the runtime environment, the exception thrown by QuestPDF provides all fonts available.
Fixed: a rare case when the Inlined
element throws the layout overflow exception when generating PDF document.
Fixed: memory leak introduced in the 2022.6 release connected to the HarfBuzzSharp library usage.
Fixed: page breaking rendering does not work in very specific corner cases
Published by MarcinZiabek over 2 years ago
Integrated the text-shaping algorithm. This change significantly improves the Unicode compatibility. Also, it extends support for more advanced languages (e.g. Arabic) that:
Improved the exception message when SkiaSharp throws the TypeInitializationException. On some operating systems, SkiaSharp requires additional dependencies installed as nuget packages. This change should help developers determine how to choose and install them correctly.
Fixed: a rare case when the Row.AutoItem() does not correctly calculate the width of its content.
Fixed: the QuestPDF Previewer does not work with content-rich documents.
Published by MarcinZiabek over 2 years ago
Published by MarcinZiabek over 2 years ago
QuestPDF: throw an exception when cannot connect to the previewer tool within 10 seconds after launching it.
QuestPDF Previewer: hide the "Generate PDF and show in default browser" button when no ducument is loaded.
Published by MarcinZiabek over 2 years ago
🎊 Release theme:
Introduced the QuestPDF Previewer
tool - a hot-reload powered, cross-platform program that visualizes your PDF document and updates its preview every time you make a code change. You don't need to recompile your code after every small adjustment. Save time and enjoy the design process! (available only for dotnet 6 and beyond)
Special thanks to Bennet Fenner
who came up with the idea, implemented the prototype, actively discussed architectural concepts, and took a crucial role in the testing phase. People like him make open-source a joy!
Other changes:
Published by MarcinZiabek over 2 years ago
Text
element, e.g. you can implement roman literal style if required,Section
element (previously the Location
element) by tracking: beginning page number, end page number, page length, page number within location,ExternalLink
element was renamed to the Hyperlink
element,Location
element was renamed to the Section
element,InternalLink
element was renamed to the SectionLink
element,