Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8551e1f33f | |||
| 3d0ca07b43 | |||
| a67fa754af | |||
| 208235ad1e |
@@ -16,7 +16,7 @@ namespace QuestPDF.Examples
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(x => GenerateStructure(x, 16));
|
||||
.Render(x => GenerateStructure(x, 12));
|
||||
}
|
||||
|
||||
private void GenerateStructure(IContainer container, int level)
|
||||
|
||||
@@ -742,7 +742,7 @@ namespace QuestPDF.Examples
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.PaddingLeft(75)
|
||||
.PaddingLeft(50)
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace QuestPDF.Examples.Engine
|
||||
private bool ApplyCaching { get; set; }
|
||||
private bool ApplyDebugging { get; set; }
|
||||
private RenderingTestResult ResultType { get; set; } = RenderingTestResult.Images;
|
||||
|
||||
private bool ShowingResultsEnabled = true;
|
||||
|
||||
private RenderingTest()
|
||||
{
|
||||
@@ -114,7 +116,7 @@ namespace QuestPDF.Examples.Engine
|
||||
Func<int, string> fileNameSchema = i => $"{FileNamePrefix}-${i}.png";
|
||||
document.GenerateImages(fileNameSchema);
|
||||
|
||||
if (ShowResult)
|
||||
if (ShowResult && ShowingResultsEnabled)
|
||||
Process.Start("explorer", fileNameSchema(0));
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ namespace QuestPDF.Examples.Engine
|
||||
var fileName = $"{FileNamePrefix}.pdf";
|
||||
document.GeneratePdf(fileName);
|
||||
|
||||
if (ShowResult)
|
||||
if (ShowResult && ShowingResultsEnabled)
|
||||
Process.Start("explorer", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,5 +339,37 @@ namespace QuestPDF.Examples
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DrawingNullTextShouldNotThrowException()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Text(null);
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.Span(null);
|
||||
text.Line(null);
|
||||
text.Hyperlink(null, "http://www.questpdf.com");
|
||||
text.TotalPages().Format(x => null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Diagnostics;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.Previewer;
|
||||
|
||||
Document
|
||||
.Create(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A4);
|
||||
page.Margin(2, Unit.Centimetre);
|
||||
page.PageColor(Colors.White);
|
||||
page.DefaultTextStyle(x => x.FontSize(14));
|
||||
|
||||
page.Header()
|
||||
.Text("Hello PDF!")
|
||||
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
|
||||
|
||||
page.Content()
|
||||
.PaddingVertical(1, Unit.Centimetre)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.ConstantColumn(30);
|
||||
columns.RelativeColumn();
|
||||
columns.ConstantColumn(75);
|
||||
columns.ConstantColumn(75);
|
||||
columns.ConstantColumn(75);
|
||||
});
|
||||
|
||||
table.Header(header =>
|
||||
{
|
||||
var textStyle = TextStyle.Default.SemiBold();
|
||||
|
||||
header.Cell().Element(DefaultCellStyle).Text("#").Style(textStyle);
|
||||
header.Cell().Element(DefaultCellStyle).Text("Item name").Style(textStyle);
|
||||
header.Cell().Element(DefaultCellStyle).AlignRight().Text("Price").Style(textStyle);
|
||||
header.Cell().Element(DefaultCellStyle).AlignRight().Text("Count").Style(textStyle);
|
||||
header.Cell().Element(DefaultCellStyle).AlignRight().Text("Total").Style(textStyle);
|
||||
|
||||
static IContainer DefaultCellStyle(IContainer container)
|
||||
{
|
||||
return container.PaddingBottom(5).BorderBottom(1).PaddingBottom(5);
|
||||
}
|
||||
});
|
||||
|
||||
foreach(var i in Enumerable.Range(1, 100))
|
||||
{
|
||||
var price = Placeholders.Random.Next(100, 999) / 100f;
|
||||
var count = Placeholders.Random.Next(1, 10);
|
||||
var total = price * count;
|
||||
|
||||
table.Cell().Element(DefaultCellStyle).Text(i);
|
||||
table.Cell().Element(DefaultCellStyle).Text(Placeholders.Label());
|
||||
table.Cell().Element(DefaultCellStyle).AlignRight().Text($"{price:N2} $");
|
||||
table.Cell().Element(DefaultCellStyle).AlignRight().Text(count);
|
||||
table.Cell().Element(DefaultCellStyle).AlignRight().Text($"{total:N2} $");
|
||||
|
||||
static IContainer DefaultCellStyle(IContainer container)
|
||||
{
|
||||
return container.PaddingBottom(5).BorderBottom(1).BorderColor(Colors.Grey.Lighten1).PaddingBottom(5);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
page.Footer()
|
||||
.AlignCenter()
|
||||
.Text(x =>
|
||||
{
|
||||
x.Span("Page ");
|
||||
x.CurrentPageNumber();
|
||||
x.Span(" of ");
|
||||
x.TotalPages();
|
||||
});
|
||||
});
|
||||
})
|
||||
.ShowInPreviewer();
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QuestPDF.Previewer\QuestPDF.Previewer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="HotReloadManager.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,125 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Previewer;
|
||||
|
||||
public static class DocumentPreviewerExtensions
|
||||
{
|
||||
public static void ShowInPreviewer(this IDocument document)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(document);
|
||||
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
var app = builder.Build();
|
||||
|
||||
var pdfDocumentCache = GeneratePdf(document);
|
||||
var refreshFlag = false;
|
||||
|
||||
static byte[] GenerateDocumentAboutException(Exception exception)
|
||||
{
|
||||
return Document.Create(document =>
|
||||
{
|
||||
document.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A4);
|
||||
page.Margin(1, Unit.Inch);
|
||||
page.PageColor(Colors.Red.Lighten4);
|
||||
page.DefaultTextStyle(x => x.FontSize(16));
|
||||
|
||||
page.Header()
|
||||
.BorderBottom(2)
|
||||
.BorderColor(Colors.Red.Medium)
|
||||
.PaddingBottom(5)
|
||||
.Text("Ooops! Something went wrong...").FontSize(28).FontColor(Colors.Red.Medium).Bold();
|
||||
|
||||
page.Content().PaddingVertical(20).Column(column =>
|
||||
{
|
||||
var currentException = exception;
|
||||
|
||||
while (currentException != null)
|
||||
{
|
||||
column.Item().Text(exception.GetType().Name).FontSize(20).SemiBold();
|
||||
column.Item().Text(exception.Message).FontSize(14);
|
||||
column.Item().PaddingTop(10).Text(exception.StackTrace).FontSize(10).Light();
|
||||
|
||||
currentException = currentException.InnerException;
|
||||
|
||||
if (currentException != null)
|
||||
column.Item().PaddingVertical(15).LineHorizontal(2).LineColor(Colors.Red.Medium);
|
||||
}
|
||||
});
|
||||
});
|
||||
}).GeneratePdf();
|
||||
}
|
||||
|
||||
static byte[] GeneratePdf(IDocument document)
|
||||
{
|
||||
try
|
||||
{
|
||||
return document.GeneratePdf();
|
||||
}
|
||||
catch(Exception exception)
|
||||
{
|
||||
return GenerateDocumentAboutException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
HotReloadManager.OnApplicationChanged += () =>
|
||||
{
|
||||
pdfDocumentCache = GeneratePdf(document);
|
||||
refreshFlag = true;
|
||||
};
|
||||
|
||||
app.MapGet("/", () =>
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = "QuestPDF.Previewer.index.html";
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
using var reader = new StreamReader(stream);
|
||||
var result = reader.ReadToEnd();
|
||||
return Results.Content(result, "text/html");
|
||||
});
|
||||
|
||||
app.MapGet("/render", () =>
|
||||
{
|
||||
refreshFlag = false;
|
||||
return Results.File(pdfDocumentCache, "application/pdf");
|
||||
});
|
||||
|
||||
app.MapGet("/listen", async () =>
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, 1000))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(100));
|
||||
|
||||
if (!refreshFlag)
|
||||
continue;
|
||||
|
||||
return Results.Text("true");
|
||||
}
|
||||
|
||||
return Results.Text("false");
|
||||
});
|
||||
|
||||
app.Lifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
var openBrowserProcess = new Process()
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = app.Urls.First()
|
||||
}
|
||||
};
|
||||
|
||||
openBrowserProcess.Start();
|
||||
});
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
[assembly: MetadataUpdateHandler(typeof(HotReloadManager))]
|
||||
|
||||
internal static class HotReloadManager
|
||||
{
|
||||
public static event Action? OnApplicationChanged;
|
||||
public static void UpdateApplication(Type[]? _) => OnApplicationChanged?.Invoke();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="index.html" />
|
||||
<EmbeddedResource Include="index.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="appsettings.Development.json" />
|
||||
<Content Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>QuestPDF Previewer</title>
|
||||
|
||||
<style>
|
||||
html {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
embed {
|
||||
border: none;
|
||||
|
||||
position: absolute;
|
||||
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.alert {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
padding: 8px 16px;
|
||||
color: #FFFA;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
box-shadow: 0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12) !important;
|
||||
}
|
||||
|
||||
#recommended-alert {
|
||||
background-color: #616161;
|
||||
}
|
||||
|
||||
#recommended-alert .close {
|
||||
color: #FFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#connection-issue-alert {
|
||||
visibility: hidden;
|
||||
background-color: #B71C1C;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<embed id="previewer" src="/render#toolbar=0&scrollbar=0" />
|
||||
|
||||
<div id="recommended-alert" class="alert">
|
||||
The recommended browser for this previewer is Microsoft Edge. It does preserve document scroll position when refreshing document, giving better overall experience.
|
||||
<a class="close" onclick="closeRecommendation()">Click to close</a>
|
||||
</div>
|
||||
|
||||
<div id="connection-issue-alert" class="alert">
|
||||
Cannot connect to QuestPDF previewer host. Possibly your debugging session has ended. Please close this browser.
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const recommendationAlert = document.getElementById("recommended-alert");
|
||||
const connectionIssueAlert = document.getElementById("connection-issue-alert");
|
||||
|
||||
function closeRecommendation() {
|
||||
recommendationAlert.parentElement.removeChild(recommendationAlert);
|
||||
localStorage.setItem("show-recommendation-alert", 'false');
|
||||
}
|
||||
|
||||
function refreshRecommendation() {
|
||||
const showRecommendation = localStorage.getItem("show-recommendation-alert");
|
||||
|
||||
if (showRecommendation !== 'false')
|
||||
return;
|
||||
|
||||
recommendationAlert.parentElement.removeChild(recommendationAlert);
|
||||
}
|
||||
|
||||
function changeConnectionIssueAlertVisibility(show) {
|
||||
connectionIssueAlert.style.setProperty("visibility", show ? "visible" : "hidden");
|
||||
}
|
||||
|
||||
async function refreshDocumentLoop() {
|
||||
window.addEventListener("change", () => reloading = true);
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const response = await fetch('/listen');
|
||||
const value = await response.text();
|
||||
|
||||
if (value === "true")
|
||||
window.location.reload();
|
||||
|
||||
changeConnectionIssueAlertVisibility(false);
|
||||
}
|
||||
catch {
|
||||
changeConnectionIssueAlertVisibility(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refreshRecommendation();
|
||||
refreshDocumentLoop();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,6 +8,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPDF.UnitTests", "Quest
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPDF.Examples", "QuestPDF.Examples\QuestPDF.Examples.csproj", "{8BD0A2B4-2DC1-47BA-9724-C158320D9CAE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPDF.Previewer", "QuestPDF.Previewer\QuestPDF.Previewer.csproj", "{B4D3CBBC-2F38-434F-9347-6E5297737047}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPDF.Previewer.Example", "QuestPDF.Previewer.Example\QuestPDF.Previewer.Example.csproj", "{012F05A0-C30B-4112-8EB0-E70CE1D31E57}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -30,5 +34,13 @@ Global
|
||||
{8BD0A2B4-2DC1-47BA-9724-C158320D9CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BD0A2B4-2DC1-47BA-9724-C158320D9CAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8BD0A2B4-2DC1-47BA-9724-C158320D9CAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4D3CBBC-2F38-434F-9347-6E5297737047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B4D3CBBC-2F38-434F-9347-6E5297737047}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B4D3CBBC-2F38-434F-9347-6E5297737047}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B4D3CBBC-2F38-434F-9347-6E5297737047}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{012F05A0-C30B-4112-8EB0-E70CE1D31E57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{012F05A0-C30B-4112-8EB0-E70CE1D31E57}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{012F05A0-C30B-4112-8EB0-E70CE1D31E57}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{012F05A0-C30B-4112-8EB0-E70CE1D31E57}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -11,19 +11,19 @@ namespace QuestPDF.Elements.Text.Items
|
||||
|
||||
public override TextMeasurementResult? Measure(TextMeasurementRequest request)
|
||||
{
|
||||
SetPageNumber(request.PageContext);
|
||||
UpdatePageNumberText(request.PageContext);
|
||||
return MeasureWithoutCache(request);
|
||||
}
|
||||
|
||||
public override void Draw(TextDrawingRequest request)
|
||||
{
|
||||
SetPageNumber(request.PageContext);
|
||||
UpdatePageNumberText(request.PageContext);
|
||||
base.Draw(request);
|
||||
}
|
||||
|
||||
private void SetPageNumber(IPageContext context)
|
||||
private void UpdatePageNumberText(IPageContext context)
|
||||
{
|
||||
Text = Source(context) ?? PageNumberPlaceholder;
|
||||
Text = Source(context) ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public class TextPageNumberDescriptor : TextSpanDescriptor
|
||||
{
|
||||
internal PageNumberFormatter FormatFunction { get; private set; } = x => (x ?? 123).ToString();
|
||||
internal PageNumberFormatter FormatFunction { get; private set; } = x => x?.ToString() ?? string.Empty;
|
||||
|
||||
internal TextPageNumberDescriptor(TextStyle textStyle) : base(textStyle)
|
||||
{
|
||||
@@ -92,6 +92,10 @@ namespace QuestPDF.Fluent
|
||||
public TextSpanDescriptor Span(string? text)
|
||||
{
|
||||
var style = DefaultStyle.Clone();
|
||||
var descriptor = new TextSpanDescriptor(style);
|
||||
|
||||
if (text == null)
|
||||
return descriptor;
|
||||
|
||||
var items = text
|
||||
.Replace("\r", string.Empty)
|
||||
@@ -114,7 +118,7 @@ namespace QuestPDF.Fluent
|
||||
.ToList()
|
||||
.ForEach(TextBlocks.Add);
|
||||
|
||||
return new TextSpanDescriptor(style);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public TextSpanDescriptor Line(string? text)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF</PackageId>
|
||||
<Version>2022.3.0</Version>
|
||||
<Version>2022.3.1</Version>
|
||||
<PackageDescription>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.</PackageDescription>
|
||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||
<LangVersion>9</LangVersion>
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
<a href="https://www.questpdf.com/" target="_blank">
|
||||
<img src="https://github.com/QuestPDF/example-invoice/raw/main/images/logo.svg" width="300">
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
[](https://www.nuget.org/packages/QuestPDF/)
|
||||
[](https://github.com/QuestPDF/QuestPDF/stargazers)
|
||||
[](https://www.nuget.org/packages/QuestPDF/)
|
||||
@@ -34,22 +28,22 @@ dotnet add package QuestPDF
|
||||
|
||||
## Documentation
|
||||
|
||||
[](https://www.questpdf.com/documentation/getting-started.html)
|
||||
[](https://www.questpdf.com/documentation/getting-started.html)
|
||||
A short and easy to follow tutorial showing how to design an invoice document under 200 lines of code.
|
||||
|
||||
|
||||
[](https://www.questpdf.com/documentation/api-reference.html)
|
||||
[](https://www.questpdf.com/documentation/api-reference.html)
|
||||
A detailed description of behavior of all available components and how to use them with C# Fluent API.
|
||||
|
||||
|
||||
[](https://www.questpdf.com/documentation/patterns-and-practices.html#document-metadata)
|
||||
[](https://www.questpdf.com/documentation/patterns-and-practices.html#document-metadata)
|
||||
Everything that may help you designing great reports and create reusable code that is easy to maintain.
|
||||
|
||||
## Simplicity is the key
|
||||
|
||||
How easy it is to start and prototype with QuestPDF? Really easy thanks to its minimal API! Please analyse the code below:
|
||||
|
||||
```csharp
|
||||
```#
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -92,10 +86,10 @@ Document.Create(container =>
|
||||
|
||||
And compare it to the produced PDF file:
|
||||
|
||||
<img src="https://github.com/QuestPDF/example-invoice/raw/main/images/minimal-api.png" width="300px">
|
||||

|
||||
|
||||
## Are you ready for more?
|
||||
|
||||
The Fluent API of QuestPDF scales really well. It is easy to create and maintain even most complex documents. Read [the Getting started tutorial](https://www.questpdf.com/documentation/getting-started.html) to learn QuestPDF basics and implement an invoice under 200 lines of code. You can also investigate and play with the code from [the example repository](https://github.com/QuestPDF/example-invoice).
|
||||
|
||||
<img src="https://github.com/QuestPDF/example-invoice/raw/main/images/invoice.png" width="400px">
|
||||

|
||||
|
||||
@@ -53,21 +53,24 @@ Install-Package QuestPDF
|
||||
dotnet add package QuestPDF
|
||||
|
||||
// Package reference in .csproj file
|
||||
<PackageReference Include="QuestPDF" Version="2022.3.0" />
|
||||
<PackageReference Include="QuestPDF" Version="2022.3.1" />
|
||||
```
|
||||
|
||||
[](https://www.nuget.org/packages/QuestPDF/)
|
||||
|
||||
## Documentation
|
||||
|
||||
[](https://www.questpdf.com/documentation/getting-started.html)
|
||||
[](https://www.questpdf.com/documentation/getting-started.html)
|
||||
A short and easy to follow tutorial showing how to design an invoice document under 200 lines of code.
|
||||
|
||||
|
||||
[](https://www.questpdf.com/documentation/api-reference.html)
|
||||
[](https://www.questpdf.com/documentation/api-reference.html)
|
||||
A detailed description of behavior of all available components and how to use them with C# Fluent API.
|
||||
|
||||
|
||||
[](https://www.questpdf.com/documentation/patterns-and-practices.html#document-metadata)
|
||||
Everything that may help you designing great reports and create reusable code that is easy to maintain.
|
||||
[](https://www.questpdf.com/documentation/patterns-and-practices.html#document-metadata)
|
||||
Everything that may help you designing great reports and create reusable code that is easy to maintain.
|
||||
|
||||
|
||||
<!-- 🚀 📖 ℹ️-->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user