Compare commits

..

1 Commits

Author SHA1 Message Date
MarcinZiabek d39819bf8d Optimized drawing border 2021-12-26 21:32:49 +01:00
358 changed files with 4248 additions and 12648 deletions
-1
View File
@@ -1 +0,0 @@
github: QuestPDF
-70
View File
@@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '22 16 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'csharp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
-54
View File
@@ -1,54 +0,0 @@
name: Build And Create Nuget Package
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
schedule:
- cron: '3 0 * * 0'
jobs:
main:
runs-on: ${{ matrix.environment }}
strategy:
matrix:
environment:
- macos-latest
- ubuntu-latest
- windows-latest
env:
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
UNIT_TEST_PROJECT: QuestPDF.UnitTests/QuestPDF.UnitTests.csproj
steps:
- name: 📝 Fetch Sources 📝
uses: actions/checkout@v2
- name: ⚙ Setup .NET 6.0 SDK ⚙
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
- name: 🔄 Restore Nuget Packages 🔄
shell: bash
run: dotnet restore
working-directory: ./Source
- name: 🛠 Build Solution 🛠
shell: bash
run: dotnet build -c Release --no-restore
working-directory: ./Source
- name: Upload build artifacts
uses: actions/upload-artifact@v3
if: ${{ matrix.environment == 'windows-latest' }}
with:
name: Build Package
path: |
**/*.nupkg
**/*.snupkg
!.nuget
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 QuestPDF
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-13
View File
@@ -1,13 +0,0 @@
# QuestPDF Community MIT License
## License Permissions
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
## Copyright
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
## Limitation Of Liability
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,29 +0,0 @@
# QuestPDF Professional And Enterprise Use License
## Do No Harm
By downloading or using the Software, the Licensee agrees not to utilize the software in a manner which is disparaging to QuestPDF, and not to rent, lease or otherwise transfer rights to the Software.
## License Permissions
Grants the use of the Software by a specified number of developers to create and deploy closed-source software for unlimited end user organizations ("The Organization") in multiple locations. This license covers unlimited applications or projects. The Software may be deployed upon any number of machines for the end-use of The Organization. This license also intrinsically covers for development, staging and production servers for each project.
Grants the use of the Software by a specified number of developers to create and deploy closed-source software for unlimited end user organizations ("The Organization") in multiple locations. This license covers unlimited applications or projects. The Software may be deployed upon any number of machines for the end-use of The Organization. This license also intrinsically covers for development, staging and production servers for each project.
## License Fees
A. If you wish to use the Software in a production environment, you may download and use the Software for one year upon payment of the appropriate license fee as indicated on the pricing page in accordance with the terms and conditions of this Agreement.
B. If you wish to use the Software in a non-production environment, you may download and access the source and/or binaries at no charge solely for testing and evaluation purposes and in accordance with all license limitations and restrictions set forth in this Agreement.
## Ownership
QuestPDF shall at all times retain ownership of the QuestPDF Software library and all subsequent copies.
## Copyright
Title, ownership rights, and intellectual property rights in and to the Software shall remain with QuestPDF. The Software is protected by the international copyright laws. Title, ownership rights, and intellectual property rights in and to the content accessed through the Software is the property of the applicable content owner and may be protected by applicable copyright or other law. This License gives you no rights to such content.
## Limitation Of Liability
THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. QUESTPDF AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL QUESTPDF OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF QUESTPDF HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-23
View File
@@ -1,23 +0,0 @@
# What License Do You Need?
## General License Overview
Open-source projects are an important foundation for the software development ecosystem. Modern applications are depending more and more upon the work of enthusiast and experts. Open-source is not anymore just sharing knowledge and passion with everybody. Over last years, maintaining and developing those projects have became a highly responsible task.
We identify the importance of the QuestPDF library in your projects, and therefore want to make sure you can safely and confidently continue the development. We strongly believe that a dual-licensing model is the best solution for all users: providing the best development experience and feature set for everybody and every project, but also offering stability for every professional and enterprise product.
Being a healthy and growing community is our primary goal that motivates us to pursue professionalism.
[Read more about exact terms](https://www.questpdf.com/pricing.html)
## QuestPDF Professional Or Enterprise Use License
If you are consuming the QuestPDF library as a Direct Package Dependency for usage in a Closed Source software in the capacity of a for-profit company/individual with more than 1M USD annual gross revenue, you must purchase the `QuestPDF Professional or Enterprise` License, depending on number of software developers. [Read more](https://www.questpdf.com/license-commercial.html)
## QuestPDF Community MIT License
We love and highly appreciate the .NET Community and therefore the vast majority of users are welcome to use the library completely for free. If you do not meet the criteria described above, you are eligible to use the `QuestPDF Community MIT` License, without any limitations, even for commercial usage. [Read more](https://www.questpdf.com/license-community.html)
If you still want to support library development, please consider purchasing the Professional License.
@@ -8,16 +8,16 @@ using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class BarcodeExamples
public class BarCode
{
[Test]
public void Example()
{
FontManager.RegisterFont(File.OpenRead("LibreBarcode39-Regular.ttf"));
FontManager.RegisterFontType("LibreBarcode39", File.OpenRead("LibreBarcode39-Regular.ttf"));
RenderingTest
.Create()
.PageSize(400, 200)
.PageSize(400, 100)
.ShowResults()
.Render(container =>
{
@@ -25,9 +25,7 @@ namespace QuestPDF.Examples
.Background(Colors.White)
.AlignCenter()
.AlignMiddle()
.Text("*QuestPDF*")
.FontFamily("Libre Barcode 39")
.FontSize(64);
.Text("*QuestPDF*", TextStyle.Default.FontType("LibreBarcode39").Size(64));
});
}
}
+31
View File
@@ -0,0 +1,31 @@
using NUnit.Framework;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
[TestFixture]
public class BarcodeExamples
{
[Test]
public void Barcode()
{
RenderingTest
.Create()
.PageSize(300, 300)
.Render(container =>
{
container
.Background("#FFF")
.Padding(25)
.Stack(stack =>
{
stack.Item().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Text("Barcode Example");
stack.Item().Border(1).Padding(5).AlignCenter().Text("*123456789*", TextStyle.Default.FontType("CarolinaBar-Demo-25E2").Size(20));
});
});
}
}
}
@@ -52,17 +52,14 @@ namespace QuestPDF.Examples
container
.Background(Colors.White)
.Padding(25)
.Column(column =>
.Stack(stack =>
{
column
stack
.Item()
.PaddingBottom(10)
.Text("Chart example")
.FontSize(20)
.SemiBold()
.FontColor(Colors.Blue.Medium);
.Text("Chart example", TextStyle.Default.Size(20).SemiBold().Color(Colors.Blue.Medium));
column
stack
.Item()
.Border(1)
.ExtendHorizontal()
@@ -16,7 +16,7 @@ namespace QuestPDF.Examples
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.Render(x => GenerateStructure(x, 12));
.Render(x => GenerateStructure(x, 16));
}
private void GenerateStructure(IContainer container, int level)
@@ -36,8 +36,8 @@ namespace QuestPDF.Examples
.BorderColor(Colors.Black)
.Row(row =>
{
row.RelativeItem().Element(x => GenerateStructure(x, level));
row.RelativeItem().Element(x => GenerateStructure(x, level));
row.RelativeColumn().Element(x => GenerateStructure(x, level));
row.RelativeColumn().Element(x => GenerateStructure(x, level));
});
}
else
@@ -45,10 +45,10 @@ namespace QuestPDF.Examples
container
.Border(level / 4f)
.BorderColor(Colors.Black)
.Column(column =>
.Stack(stack =>
{
column.Item().Element(x => GenerateStructure(x, level));
column.Item().Element(x => GenerateStructure(x, level));
stack.Item().Element(x => GenerateStructure(x, level));
stack.Item().Element(x => GenerateStructure(x, level));
});
}
}
@@ -22,10 +22,10 @@ namespace QuestPDF.Examples
page.Header().Text("Header");
page.Content().PaddingVertical(10).Border(1).Padding(10).Column(column =>
page.Content().PaddingVertical(10).Border(1).Padding(10).Stack(stack =>
{
foreach (var index in Enumerable.Range(1, 100))
column.Item().Text($"Line {index}").FontColor(Placeholders.Color());
stack.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color()));
});
page.Footer().Text("Footer");
@@ -9,7 +9,7 @@ namespace QuestPDF.Examples
public class DebuggingTesting
{
[Test]
public void Column()
public void Stack()
{
Assert.Throws<DocumentLayoutException>(() =>
{
@@ -23,7 +23,7 @@ namespace QuestPDF.Examples
.Width(100)
.Background(Colors.Grey.Lighten3)
.DebugPointer("Example debug pointer")
.Column(x =>
.Stack(x =>
{
x.Item().Text("Test");
x.Item().Width(150);
@@ -13,7 +13,7 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
.ProducePdf()
.ProduceImages()
.ShowResults()
.RenderDocument(container =>
{
@@ -24,13 +24,13 @@ namespace QuestPDF.Examples
page.Margin(20);
page.Size(PageSizes.A4);
page.PageColor(Colors.White);
page.Background(Colors.White);
page.Content().Column(column =>
page.Content().Stack(stack =>
{
column.Item().Text(Placeholders.Sentence());
stack.Item().Text(Placeholders.Sentence());
column.Item().Text(text =>
stack.Item().Text(text =>
{
// text in this block is additionally semibold
text.DefaultTextStyle(TextStyle.Default.SemiBold());
@@ -38,7 +38,7 @@ namespace QuestPDF.Examples
text.Line(Placeholders.Sentence());
// this text has size 20 but also semibold and red
text.Span(Placeholders.Sentence()).FontColor(Colors.Red.Medium);
text.Span(Placeholders.Sentence(), TextStyle.Default.Color(Colors.Red.Medium));
});
});
});
@@ -40,12 +40,10 @@ namespace QuestPDF.Examples
.Decoration(decoration =>
{
decoration
.Before()
.Header()
.Background(Colors.Grey.Medium)
.Padding(10)
.Text("Notes")
.FontSize(16)
.FontColor("#FFF");
.Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
decoration
.Content()
@@ -68,27 +66,27 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(20)
.Column(column =>
.Stack(stack =>
{
column.Item()
stack.Item()
.PaddingBottom(10)
.AlignCenter()
.Text("This Row element is 700pt wide");
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.ConstantItem(100)
row.ConstantColumn(100)
.Background(Colors.Grey.Lighten1)
.Padding(10)
.ExtendVertical()
.Text("This column is 100 pt wide");
row.RelativeItem()
row.RelativeColumn()
.Background(Colors.Grey.Lighten2)
.Padding(10)
.Text("This column takes 1/3 of the available space (200pt)");
row.RelativeItem(2)
row.RelativeColumn(2)
.Background(Colors.Grey.Lighten3)
.Padding(10)
.Text("This column takes 2/3 of the available space (400pt)");
@@ -111,15 +109,15 @@ namespace QuestPDF.Examples
.Row(row =>
{
row.Spacing(20);
row.RelativeItem(2).Border(1).Background(Colors.Grey.Lighten1);
row.RelativeItem(3).Border(1).Background(Colors.Grey.Lighten2);
row.RelativeItem(4).Border(1).Background(Colors.Grey.Lighten3);
row.RelativeColumn(2).Border(1).Background(Colors.Grey.Lighten1);
row.RelativeColumn(3).Border(1).Background(Colors.Grey.Lighten2);
row.RelativeColumn(4).Border(1).Background(Colors.Grey.Lighten3);
});
});
}
[Test]
public void column()
public void Stack()
{
RenderingTest
.Create()
@@ -129,13 +127,13 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(15)
.Column(column =>
.Stack(stack =>
{
column.Spacing(15);
stack.Spacing(15);
column.Item().Background(Colors.Grey.Medium).Height(50);
column.Item().Background(Colors.Grey.Lighten1).Height(100);
column.Item().Background(Colors.Grey.Lighten2).Height(150);
stack.Item().Background(Colors.Grey.Medium).Height(50);
stack.Item().Background(Colors.Grey.Lighten1).Height(100);
stack.Item().Background(Colors.Grey.Lighten2).Height(150);
});
});
}
@@ -269,12 +267,12 @@ namespace QuestPDF.Examples
layers
.PrimaryLayer()
.Padding(25)
.Column(column =>
.Stack(stack =>
{
column.Spacing(5);
stack.Spacing(5);
foreach (var _ in Enumerable.Range(0, 7))
column.Item().Text(Placeholders.Sentence());
stack.Item().Text(Placeholders.Sentence());
});
// layer above the main content
@@ -282,15 +280,12 @@ namespace QuestPDF.Examples
.Layer()
.AlignCenter()
.AlignMiddle()
.Text("Watermark")
.FontSize(48)
.Bold()
.FontColor(Colors.Green.Lighten3);
.Text("Watermark", TextStyle.Default.Size(48).Bold().Color(Colors.Green.Lighten3));
layers
.Layer()
.AlignBottom()
.Text(text => text.CurrentPageNumber().FontSize(16).FontColor(Colors.Green.Medium));
.Text(text => text.CurrentPageNumber(TextStyle.Default.Size(16).Color(Colors.Green.Medium)));
});
});
}
@@ -309,16 +304,16 @@ namespace QuestPDF.Examples
// {
// page.Header().PageNumber("Page {pdf:currentPage}");
//
// page.Content().Height(300).column(content =>
// page.Content().Height(300).Stack(content =>
// {
// content.Item().Height(200).Background(Colors.Grey.Lighten2);
//
// content.Item().EnsureSpace(100).column(column =>
// content.Item().EnsureSpace(100).Stack(stack =>
// {
// column.Spacing(10);
// stack.Spacing(10);
//
// foreach (var _ in Enumerable.Range(0, 4))
// column.Item().Height(50).Background(Colors.Green.Lighten1);
// stack.Item().Height(50).Background(Colors.Green.Lighten1);
// });
// });
// });
@@ -383,7 +378,7 @@ namespace QuestPDF.Examples
.Row(row =>
{
foreach (var color in colors)
row.RelativeItem().Background(color);
row.RelativeColumn().Background(color);
});
});
}
@@ -421,9 +416,7 @@ namespace QuestPDF.Examples
.Border(1)
.BorderColor(Colors.Grey.Medium)
.Padding(10)
.Text(font)
.FontFamily(font)
.FontSize(16);
.Text(font, TextStyle.Default.FontType(font).Size(16));
}
});
});
@@ -444,10 +437,10 @@ namespace QuestPDF.Examples
{
layers.Layer().Text("Something else");
layers.PrimaryLayer().Column(column =>
layers.PrimaryLayer().Stack(stack =>
{
column.Item().PaddingTop(20).Text("Text 1");
column.Item().PaddingTop(40).Text("Text 2");
stack.Item().PaddingTop(20).Text("Text 1");
stack.Item().PaddingTop(40).Text("Text 2");
});
layers.Layer().Canvas((canvas, size) =>
@@ -463,7 +456,7 @@ namespace QuestPDF.Examples
});
layers.Layer().Background("#8F00").Extend();
layers.Layer().PaddingTop(40).Text("It works!").FontSize(24);
layers.Layer().PaddingTop(40).Text("It works!", TextStyle.Default.Size(24));
});
});
}
@@ -481,10 +474,10 @@ namespace QuestPDF.Examples
.Padding(15)
.Border(4)
.BorderColor(Colors.Blue.Medium)
//.MinimalBox()
//.Box()
.Background(Colors.Grey.Lighten2)
.Padding(15)
.Text("Test of the \n box element").FontSize(20);
.Text("Test of the \n box element", TextStyle.Default.Size(20));
});
}
@@ -508,14 +501,13 @@ namespace QuestPDF.Examples
.SemiBold();
decoration
.Before()
.Header()
.PaddingBottom(10)
.Text("Example: scale component")
.Style(headerFontStyle);
.Text("Example: scale component", headerFontStyle);
decoration
.Content()
.Column(column =>
.Stack(stack =>
{
var scales = new[] { 0.8f, 0.9f, 1.1f, 1.2f };
@@ -527,14 +519,13 @@ namespace QuestPDF.Examples
var fontStyle = TextStyle.Default.Size(16);
column
stack
.Item()
.Border(1)
.Background(fontColor)
.Scale(scale)
.Padding(5)
.Text($"Content with {scale} scale.")
.Style(fontStyle);
.Text($"Content with {scale} scale.", fontStyle);
}
});
});
@@ -551,7 +542,7 @@ namespace QuestPDF.Examples
{
container
.Background("#FFF")
.MinimalBox()
.Box()
.Padding(25)
@@ -564,8 +555,7 @@ namespace QuestPDF.Examples
.BorderColor(Colors.Green.Darken1)
.Padding(50)
.Text("Moved text")
.FontSize(25);
.Text("Moved text", TextStyle.Default.Size(25));
});
}
@@ -598,11 +588,10 @@ namespace QuestPDF.Examples
return element;
})
.MinimalBox()
.Box()
.Background(Colors.White)
.Padding(10)
.Text($"Rotated {turns * 90}°")
.FontSize(16);
.Text($"Rotated {turns * 90}°", TextStyle.Default.Size(16));
}
});
});
@@ -697,11 +686,10 @@ namespace QuestPDF.Examples
return element;
})
.MinimalBox()
.Box()
.Background(Colors.White)
.Padding(10)
.Text($"Flipped {turns}")
.FontSize(16);
.Text($"Flipped {turns}", TextStyle.Default.Size(16));
}
});
});
@@ -720,14 +708,14 @@ namespace QuestPDF.Examples
.Border(2)
.Row(row =>
{
row.ConstantItem(25)
row.ConstantColumn(25)
.Border(1)
.RotateLeft()
.AlignCenter()
.AlignMiddle()
.Text("Sample text");
row.RelativeItem().Border(1).Padding(5).Text(Placeholders.Paragraph());
row.RelativeColumn().Border(1).Padding(5).Text(Placeholders.Paragraph());
});
});
}
@@ -742,12 +730,12 @@ namespace QuestPDF.Examples
{
container
.Padding(25)
.PaddingLeft(50)
.Column(column =>
.PaddingLeft(75)
.Stack(stack =>
{
column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
column
stack
.Item()
// creates an infinite space for its child
@@ -763,7 +751,7 @@ namespace QuestPDF.Examples
.Background(Colors.Blue.Darken1);
column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
});
});
}
@@ -778,13 +766,13 @@ namespace QuestPDF.Examples
{
container
.Padding(25)
.Column(column =>
.Stack(stack =>
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem().LabelCell("Label 1");
row.RelativeColumn().LabelCell("Label 1");
row.RelativeItem(3).Grid(grid =>
row.RelativeColumn(3).Grid(grid =>
{
grid.Columns(3);
@@ -796,11 +784,11 @@ namespace QuestPDF.Examples
});
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem().ValueCell().Text("Value 1");
row.RelativeColumn().ValueCell().Text("Value 1");
row.RelativeItem(3).Grid(grid =>
row.RelativeColumn(3).Grid(grid =>
{
grid.Columns(3);
@@ -812,10 +800,10 @@ namespace QuestPDF.Examples
});
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem().LabelCell("Label 6");
row.RelativeItem().ValueCell().Text("Value 6");
row.RelativeColumn().LabelCell("Label 6");
row.RelativeColumn().ValueCell().Text("Value 6");
});
});
});
@@ -20,11 +20,7 @@ namespace QuestPDF.Examples.Engine
private Size Size { get; set; }
private int? MaxPagesThreshold { get; set; }
private bool ShowResult { get; set; }
private bool ApplyCaching { get; set; }
private bool ApplyDebugging { get; set; }
private RenderingTestResult ResultType { get; set; } = RenderingTestResult.Images;
private bool ShowingResultsEnabled = true;
private RenderingTest()
{
@@ -71,24 +67,6 @@ namespace QuestPDF.Examples.Engine
return this;
}
public RenderingTest MaxPages(int value)
{
MaxPagesThreshold = value;
return this;
}
public RenderingTest EnableCaching(bool value = true)
{
ApplyCaching = value;
return this;
}
public RenderingTest EnableDebugging(bool value = true)
{
ApplyDebugging = value;
return this;
}
public void Render(Action<IContainer> content)
{
RenderDocument(container =>
@@ -100,11 +78,16 @@ namespace QuestPDF.Examples.Engine
});
});
}
public void MaxPages(int value)
{
MaxPagesThreshold = value;
}
public void RenderDocument(Action<IDocumentContainer> content)
{
MaxPagesThreshold ??= ResultType == RenderingTestResult.Pdf ? 1000 : 10;
var document = new SimpleDocument(content, MaxPagesThreshold.Value, ApplyCaching, ApplyDebugging);
var document = new SimpleDocument(content, MaxPagesThreshold.Value);
Render(document);
}
@@ -116,7 +99,7 @@ namespace QuestPDF.Examples.Engine
Func<int, string> fileNameSchema = i => $"{FileNamePrefix}-${i}.png";
document.GenerateImages(fileNameSchema);
if (ShowResult && ShowingResultsEnabled)
if (ShowResult)
Process.Start("explorer", fileNameSchema(0));
}
@@ -125,7 +108,7 @@ namespace QuestPDF.Examples.Engine
var fileName = $"{FileNamePrefix}.pdf";
document.GeneratePdf(fileName);
if (ShowResult && ShowingResultsEnabled)
if (ShowResult)
Process.Start("explorer", fileName);
}
}
@@ -13,15 +13,11 @@ namespace QuestPDF.Examples.Engine
private Action<IDocumentContainer> Content { get; }
private int MaxPages { get; }
private bool ApplyCaching { get; }
private bool ApplyDebugging { get; }
public SimpleDocument(Action<IDocumentContainer> content, int maxPages, bool applyCaching, bool applyDebugging)
public SimpleDocument(Action<IDocumentContainer> content, int maxPages)
{
Content = content;
MaxPages = maxPages;
ApplyCaching = applyCaching;
ApplyDebugging = applyDebugging;
}
public DocumentMetadata GetMetadata()
@@ -29,9 +25,7 @@ namespace QuestPDF.Examples.Engine
return new DocumentMetadata()
{
RasterDpi = PageSizes.PointsPerInch * ImageScalingFactor,
DocumentLayoutExceptionThreshold = MaxPages,
ApplyCaching = ApplyCaching,
ApplyDebugging = ApplyDebugging
DocumentLayoutExceptionThreshold = MaxPages
};
}
@@ -21,19 +21,19 @@ namespace QuestPDF.Examples
{
page.Margin(20);
page.Size(PageSizes.A7.Landscape());
page.PageColor(Colors.White);
page.Background(Colors.White);
page.Header().Text("With ensure space").SemiBold();
page.Header().Text("With ensure space", TextStyle.Default.SemiBold());
page.Content().Column(column =>
page.Content().Stack(stack =>
{
column
stack
.Item()
.ExtendHorizontal()
.Height(75)
.Background(Colors.Grey.Lighten2);
column
stack
.Item()
.EnsureSpace(100)
.Text(Placeholders.LoremIpsum());
@@ -12,14 +12,12 @@ namespace QuestPDF.Examples
{
return container
.Border(1)
.BorderColor(Colors.Grey.Medium)
.Background(dark ? Colors.Grey.Lighten3 : Colors.White)
.Padding(5);
.Background(dark ? Colors.Grey.Lighten2 : Colors.White)
.Padding(10);
}
public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text).SemiBold();
public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text, TextStyle.Default.Medium());
public static IContainer ValueCell(this IContainer container) => container.Cell(false);
public static void ValueCell(this IContainer container, string text) => container.ValueCell().Text(text);
}
public class FrameExample
@@ -36,14 +34,14 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(25)
.Column(column =>
.Stack(stack =>
{
for(var i = 1; i <= 4; i++)
for(var i=1; i<=4; i++)
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(2).LabelCell(Placeholders.Label());
row.RelativeItem(3).ValueCell().Text(Placeholders.Paragraph());
row.RelativeColumn(2).LabelCell(Placeholders.Label());
row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph());
});
}
});
+51
View File
@@ -0,0 +1,51 @@
using System.IO;
using NUnit.Framework;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
namespace QuestPDF.Examples
{
public class ImageExamples
{
[Test]
public void LoadingImage()
{
RenderingTest
.Create()
.PageSize(PageSizes.A5)
.ProducePdf()
.ShowResults()
.Render(page =>
{
page.Padding(25).Stack(stack =>
{
stack.Spacing(25);
stack.Item().Image("logo.png");
var binaryData = File.ReadAllBytes("logo.png");
stack.Item().Image(binaryData);
using var stream = new FileStream("logo.png", FileMode.Open);
stack.Item().Image(stream);
});
});
}
[Test]
public void Exception()
{
Assert.Throws<DocumentComposeException>(() =>
{
RenderingTest
.Create()
.PageSize(PageSizes.A2)
.ProducePdf()
.ShowResults()
.Render(page => page.Image("non_existent.png"));
});
}
}
}
@@ -25,7 +25,7 @@ namespace QuestPDF.Examples
.Padding(25)
.Decoration(decoration =>
{
decoration.Before().Text(text =>
decoration.Header().Text(text =>
{
text.DefaultTextStyle(TextStyle.Default.Size(20));
@@ -37,7 +37,7 @@ namespace QuestPDF.Examples
decoration
.Content()
.PaddingTop(25)
//.MinimalBox()
//.Box()
.Border(1)
.Background(Colors.Grey.Lighten2)
.Inlined(inlined =>
@@ -74,8 +74,7 @@ namespace QuestPDF.Examples
.PrimaryLayer()
.AlignCenter()
.AlignMiddle()
.Text(sizeText)
.FontSize(15);
.Text(sizeText, TextStyle.Default.Size(15));
});
}
});
@@ -95,7 +94,7 @@ namespace QuestPDF.Examples
{
container
.Padding(20)
.MinimalBox()
.Box()
.Border(1)
.Background(Colors.Grey.Lighten4)
.Inlined(inlined =>
@@ -120,42 +119,5 @@ namespace QuestPDF.Examples
.Background(Placeholders.BackgroundColor());
}
}
[Test]
public void RepeatingInlinedInHeader_Test()
{
RenderingTest
.Create()
.ProduceImages()
.ShowResults()
.RenderDocument(document =>
{
document.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Inch);
page.PageColor(Colors.White);
page.Header()
.Inlined(inlined =>
{
inlined.Spacing(10);
foreach (var i in Enumerable.Range(5, 5))
inlined.Item().Width(i * 10).Height(20).Background(Colors.Red.Medium);
});
page.Content()
.PaddingVertical(20)
.Column(column =>
{
column.Spacing(25);
foreach (var i in Enumerable.Range(10, 20))
column.Item().Width(i * 10).Height(50).Background(Colors.Grey.Lighten2);
});
});
});
}
}
}
@@ -19,12 +19,10 @@ namespace QuestPDF.Examples
{
var url = "https://picsum.photos/300/200";
if (Greyscale)
if(Greyscale)
url += "?grayscale";
using var client = new WebClient();
client.Headers.Add("user-agent", "QuestPDF/1.0 Unit Testing");
var response = client.DownloadData(url);
container.Image(response);
}
@@ -45,7 +43,7 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(25)
.Column(column =>
.Stack(column =>
{
column.Spacing(10);
@@ -61,4 +59,4 @@ namespace QuestPDF.Examples
});
}
}
}
}
@@ -50,8 +50,7 @@ namespace QuestPDF.Examples
.Background("FFF")
.Padding(5)
.AlignCenter()
.Text("Sample text")
.FontFamily("Segoe UI emoji");
.Text("Sample text", TextStyle.Default.FontType("Segoe UI emoji"));
});
}
@@ -64,7 +63,7 @@ namespace QuestPDF.Examples
.Render(container =>
{
container
.Column(column =>
.Stack(column =>
{
column
.Item()
@@ -114,14 +113,14 @@ namespace QuestPDF.Examples
.Render(container =>
{
container
.Column(column =>
.Stack(column =>
{
column
.Item()
.Height(150)
.Row(row =>
{
row.RelativeItem()
row.RelativeColumn()
.Extend()
.Background("FFF")
@@ -129,7 +128,7 @@ namespace QuestPDF.Examples
.Width(50)
.Background("444");
row.RelativeItem()
row.RelativeColumn()
.Extend()
.Background("BBB")
@@ -143,7 +142,7 @@ namespace QuestPDF.Examples
.Height(150)
.Row(row =>
{
row.RelativeItem()
row.RelativeColumn()
.Extend()
.Background("BBB")
@@ -151,7 +150,7 @@ namespace QuestPDF.Examples
.Width(50)
.Background("444");
row.RelativeItem()
row.RelativeColumn()
.Extend()
.Background("BBB")
@@ -6,13 +6,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
<PackageReference Include="microcharts" Version="0.9.5.9" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="SkiaSharp" Version="2.88.3" />
<PackageReference Include="Svg.Skia" Version="0.5.18" />
<PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="SkiaSharp" Version="2.80.3" />
</ItemGroup>
<ItemGroup>
@@ -29,9 +27,6 @@
<None Update="logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="pdf-icon.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -21,20 +21,20 @@ namespace QuestPDF.Examples
{
page.Margin(20);
page.Size(PageSizes.A7.Landscape());
page.PageColor(Colors.White);
page.Background(Colors.White);
page.Header().Text("With show once").SemiBold();
page.Header().Text("With show once", TextStyle.Default.SemiBold());
page.Content().PaddingVertical(5).Row(row =>
{
row.RelativeItem()
row.RelativeColumn()
.Background(Colors.Grey.Lighten2)
.Border(1)
.Padding(5)
.ShowOnce()
.Text(Placeholders.Label());
row.RelativeItem(2)
row.RelativeColumn(2)
.Border(1)
.Padding(5)
.Text(Placeholders.Paragraph());
@@ -21,18 +21,17 @@ namespace QuestPDF.Examples
{
page.Margin(20);
page.Size(PageSizes.A7.Landscape());
page.PageColor(Colors.White);
page.Background(Colors.White);
page.Header().Column(column =>
page.Header().Stack(stack =>
{
column.Item().ShowOnce().Text("This header is visible on the first page.");
column.Item().SkipOnce().Text("This header is visible on the second page and all following.");
stack.Item().ShowOnce().Text("This header is visible on the first page.");
stack.Item().SkipOnce().Text("This header is visible on the second page and all following.");
});
page.Content()
.PaddingVertical(10)
.Text(Placeholders.Paragraphs())
.FontColor(Colors.Grey.Medium);
.Text(Placeholders.Paragraphs(), TextStyle.Default.Color(Colors.Grey.Medium));
page.Footer().Text(text =>
{
@@ -23,7 +23,7 @@ namespace QuestPDF.Examples
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.RenderDocument(x => ComposeBook(x, chapters));
.Render(x => ComposeBook(x, chapters));
}
[Test]
@@ -31,7 +31,7 @@ namespace QuestPDF.Examples
{
var chapters = GetBookChapters().ToList();
var results = PerformTest(128).ToList();
var results = PerformTest(16).ToList();
Console.WriteLine($"Min: {results.Min():F}");
Console.WriteLine($"Max: {results.Max():F}");
@@ -42,8 +42,8 @@ namespace QuestPDF.Examples
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProducePdf()
.RenderDocument(x => ComposeBook(x, chapters));
.ProducePdf()
.Render(x => ComposeBook(x, chapters));
}
IEnumerable<float> PerformTest(int attempts)
@@ -102,105 +102,112 @@ namespace QuestPDF.Examples
}
}
private void ComposeBook(IDocumentContainer container, ICollection<BookChapter> chapters)
private void ComposeBook(IContainer container, ICollection<BookChapter> chapters)
{
var subtitleStyle = TextStyle.Default.Size(24).SemiBold().Color(Colors.Blue.Medium);
var normalStyle = TextStyle.Default.Size(14);
ComposePage(container);
container.Page(page =>
void ComposePage(IContainer container)
{
page.Margin(50);
page.Content().PaddingVertical(10).Column(column =>
{
column.Item().Element(Title);
column.Item().PageBreak();
column.Item().Element(TableOfContents);
column.Item().PageBreak();
container
.Padding(50)
.Decoration(decoration =>
{
decoration
.Content()
.Stack(stack =>
{
stack.Item().Element(Title);
stack.Item().PageBreak();
stack.Item().Element(TableOfContents);
stack.Item().PageBreak();
Chapters(column);
Chapters(stack);
column.Item().Element(Acknowledgements);
});
page.Footer().Element(Footer);
});
stack.Item().Element(Acknowledgements);
});
decoration.Footer().Element(Footer);
});
}
void Title(IContainer container)
{
container
.Extend()
.PaddingBottom(200)
.AlignBottom()
.Column(column =>
.Stack(stack =>
{
column.Item().Text("Quo Vadis").FontSize(72).Bold().FontColor(Colors.Blue.Darken2);
column.Item().Text("Henryk Sienkiewicz").FontSize(24).FontColor(Colors.Grey.Darken2);
stack.Item().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2));
stack.Item().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2));
});
}
void TableOfContents(IContainer container)
{
container.Column(column =>
container.Stack(stack =>
{
SectionTitle(column, "Spis treści");
SectionTitle(stack, "Spis treści");
foreach (var chapter in chapters)
{
column.Item().InternalLink(chapter.Title).Row(row =>
stack.Item().InternalLink(chapter.Title).Row(row =>
{
row.RelativeItem().Text(chapter.Title).Style(normalStyle);
row.ConstantItem(100).AlignRight().Text(text => text.BeginPageNumberOfSection(chapter.Title).Style(normalStyle));
row.RelativeColumn().Text(chapter.Title, normalStyle);
row.ConstantColumn(100).AlignRight().Text(text => text.PageNumberOfLocation(chapter.Title, normalStyle));
});
}
});
}
void Chapters(ColumnDescriptor column)
void Chapters(StackDescriptor stack)
{
foreach (var chapter in chapters)
{
column.Item().Element(container => Chapter(container, chapter.Title, chapter.Content));
stack.Item().Element(container => Chapter(container, chapter.Title, chapter.Content));
}
}
void Chapter(IContainer container, string title, string content)
{
container.Column(column =>
container.Stack(stack =>
{
SectionTitle(column, title);
SectionTitle(stack, title);
column.Item().Text(text =>
stack.Item().Text(text =>
{
text.ParagraphSpacing(5);
text.Span(content).Style(normalStyle);
text.Span(content, normalStyle);
});
column.Item().PageBreak();
stack.Item().PageBreak();
});
}
void Acknowledgements(IContainer container)
{
container.Column(column =>
container.Stack(stack =>
{
SectionTitle(column, "Podziękowania");
SectionTitle(stack, "Podziękowania");
column.Item().Text(text =>
stack.Item().Text(text =>
{
text.DefaultTextStyle(normalStyle);
text.Span("Ten dokument został wygenerowany na podstawie książki w formacie TXT opublikowanej w serwisie ");
text.Hyperlink("wolnelektury.pl", "https://wolnelektury.pl/").FontColor(Colors.Blue.Medium).Underline();
text.ExternalLocation("wolnelektury.pl", "https://wolnelektury.pl/", normalStyle.Color(Colors.Blue.Medium).Underline());
text.Span(". Dziękuję za wspieranie polskiego czytelnictwa!");
});
});
}
void SectionTitle(ColumnDescriptor column, string text)
void SectionTitle(StackDescriptor stack, string text)
{
column.Item().Location(text).Text(text).Style(subtitleStyle);
column.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
stack.Item().Location(text).Text(text, subtitleStyle);
stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
}
void Footer(IContainer container)
+271
View File
@@ -0,0 +1,271 @@
using System;
using System.Linq;
using System.Text;
using NUnit.Framework;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class TextExamples
{
[Test]
public void SimpleTextBlock()
{
RenderingTest
.Create()
.PageSize(500, 300)
.ProduceImages()
.ShowResults()
.Render(container =>
{
container
.Padding(5)
.Box()
.Border(1)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default.Size(20));
text.Span("This is a normal text, followed by an ");
text.Span("underlined red text.", TextStyle.Default.Size(20).Color(Colors.Red.Medium).Underline());
});
});
}
[Test]
public void ParagraphSpacing()
{
RenderingTest
.Create()
.PageSize(500, 300)
.ProduceImages()
.ShowResults()
.Render(container =>
{
container
.Padding(5)
.Box()
.Border(1)
.Padding(10)
.Text(text =>
{
text.ParagraphSpacing(10);
foreach (var i in Enumerable.Range(1, 3))
{
text.Span($"Paragraph {i}: ", TextStyle.Default.SemiBold());
text.Line(Placeholders.Paragraph());
}
});
});
}
[Test]
public void CustomElement()
{
RenderingTest
.Create()
.PageSize(500, 200)
.ProduceImages()
.ShowResults()
.Render(container =>
{
container
.Padding(5)
.Box()
.Border(1)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default.Size(20));
text.Span("This is a random image aligned to the baseline: ");
text.Element()
.PaddingBottom(-6)
.Height(24)
.Width(48)
.Image(Placeholders.Image);
text.Span(".");
});
});
}
[Test]
public void TextElements()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.Render(container =>
{
container
.Padding(20)
.Padding(10)
.Box()
.Border(1)
.Padding(5)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default);
text.AlignLeft();
text.ParagraphSpacing(10);
text.Line(Placeholders.LoremIpsum());
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? <", TextStyle.Default.Underline());
});
});
}
[Test]
public void TextStack()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.Render(container =>
{
container
.Padding(20)
.Padding(10)
.Box()
.Border(1)
.Padding(5)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default);
text.AlignLeft();
text.ParagraphSpacing(10);
foreach (var i in Enumerable.Range(1, 100))
text.Line($"{i}: {Placeholders.Paragraph()}");
});
});
}
[Test]
public void SpaceIssue()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.Render(container =>
{
container
.Padding(20)
.Padding(10)
.Box()
.Border(1)
.Padding(5)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default);
text.AlignLeft();
text.ParagraphSpacing(10);
text.Span(Placeholders.LoremIpsum());
text.EmptyLine();
text.Span("This text is a normal text, ");
text.Span("this is a bold text, ", TextStyle.Default.Bold());
text.Span("this is a red and underlined text, ", TextStyle.Default.Color(Colors.Red.Medium).Underline());
text.Span("and this is slightly bigger text.", TextStyle.Default.Size(16));
text.EmptyLine();
text.Span("The new text element also supports injecting custom content between words: ");
text.Element().PaddingBottom(-10).Height(16).Width(32).Image(Placeholders.Image);
text.Span(".");
text.EmptyLine();
text.Span("This is page number ");
text.CurrentPageNumber();
text.Span(" out of ");
text.TotalPages();
text.EmptyLine();
text.ExternalLocation("Please visit QuestPDF website", "https://www.questpdf.com");
text.EmptyLine();
text.Span(Placeholders.Paragraphs());
text.EmptyLine();
text.Span(Placeholders.Paragraphs(), TextStyle.Default.Italic());
text.Line("This is target text that does not show up. " + Placeholders.Paragraph());
});
});
}
[Test]
public void HugeList()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProducePdf()
.ShowResults()
.Render(container =>
{
container
.Padding(20)
.Padding(10)
.Box()
.Border(1)
.Padding(5)
.Padding(10)
.Text(text =>
{
text.DefaultTextStyle(TextStyle.Default);
text.AlignLeft();
text.ParagraphSpacing(10);
text.Span("This text is a normal text, ");
text.Span("this is a bold text, ", TextStyle.Default.Bold());
text.Span("this is a red and underlined text, ", TextStyle.Default.Color(Colors.Red.Medium).Underline());
text.Span("and this is slightly bigger text.", TextStyle.Default.Size(16));
text.Span("The new text element also supports injecting custom content between words: ");
text.Element().PaddingBottom(-10).Height(16).Width(32).Image(Placeholders.Image);
text.Span(".");
text.EmptyLine();
foreach (var i in Enumerable.Range(1, 100))
{
text.Line($"{i}: {Placeholders.Paragraph()}");
text.ExternalLocation("Please visit QuestPDF website", "https://www.questpdf.com");
text.Span("This is page number ");
text.CurrentPageNumber();
text.Span(" out of ");
text.TotalPages();
text.EmptyLine();
}
});
});
}
}
}

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

+28
View File
@@ -0,0 +1,28 @@
using System;
using System.IO;
using SkiaSharp;
namespace QuestPDF.ReportSample
{
public static class Helpers
{
public static Random Random { get; } = new Random(1);
public static string GetTestItem(string path) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", path);
public static byte[] GetImage(string name)
{
var photoPath = GetTestItem(name);
return SKImage.FromEncodedData(photoPath).EncodedData.ToArray();
}
public static Location RandomLocation()
{
return new Location
{
Longitude = Helpers.Random.NextDouble() * 360f - 180f,
Latitude = Helpers.Random.NextDouble() * 180f - 90f
};
}
}
}
@@ -26,58 +26,58 @@ namespace QuestPDF.ReportSample.Layouts
private void ComposeHeader(IContainer container)
{
container.Background(Colors.Grey.Lighten3).Border(1).Column(column =>
container.Background(Colors.Grey.Lighten3).Border(1).Stack(stack =>
{
column.Item().ShowOnce().Padding(5).AlignMiddle().Row(row =>
stack.Item().ShowOnce().Padding(5).AlignMiddle().Row(row =>
{
row.RelativeItem(2).AlignMiddle().Text("PRIMARY HEADER").FontColor(Colors.Grey.Darken3).FontSize(30).Bold();
row.RelativeItem(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30);
row.RelativeColumn(2).AlignMiddle().Text("PRIMARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
row.RelativeColumn(1).AlignRight().Box().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30);
});
column.Item().SkipOnce().Padding(5).Row(row =>
stack.Item().SkipOnce().Padding(5).Row(row =>
{
row.RelativeItem(2).Text("SECONDARY HEADER").FontColor(Colors.Grey.Darken3).FontSize(30).Bold();
row.RelativeItem(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15);
row.RelativeColumn(2).Text("SECONDARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
row.RelativeColumn(1).AlignRight().Box().Background(Colors.Blue.Lighten4).Padding(15);
});
});
}
private void ComposeContent(IContainer container)
{
container.Column(column =>
container.Stack(stack =>
{
column.Item().PaddingVertical(80).Text("First");
column.Item().PageBreak();
column.Item().PaddingVertical(80).Text("Second");
column.Item().PageBreak();
column.Item().PaddingVertical(80).Text("Third");
column.Item().PageBreak();
stack.Item().PaddingVertical(80).Text("First");
stack.Item().PageBreak();
stack.Item().PaddingVertical(80).Text("Second");
stack.Item().PageBreak();
stack.Item().PaddingVertical(80).Text("Third");
stack.Item().PageBreak();
});
}
private void ComposeFooter(IContainer container)
{
container.Background(Colors.Grey.Lighten3).Column(column =>
container.Background(Colors.Grey.Lighten3).Stack(stack =>
{
column.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>
stack.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>
{
row.RelativeItem().Text(x =>
row.RelativeColumn().Text(x =>
{
x.CurrentPageNumber();
x.Span(" / ");
x.TotalPages();
});
row.RelativeItem().AlignRight().Text("Footer for header");
row.RelativeColumn().AlignRight().Text("Footer for header");
});
column.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>
stack.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>
{
row.RelativeItem().Text(x =>
row.RelativeColumn().Text(x =>
{
x.CurrentPageNumber();
x.Span(" / ");
x.TotalPages();
});
row.RelativeItem().AlignRight().Text("Footer for every page except header");
row.RelativeColumn().AlignRight().Text("Footer for every page except header");
});
});
}
@@ -1,4 +1,3 @@
using System;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
@@ -18,11 +17,11 @@ namespace QuestPDF.ReportSample.Layouts
{
container
.ShowEntire()
.Column(column =>
.Stack(stack =>
{
column.Spacing(5);
column.Item().Element(PhotoWithMaps);
column.Item().Element(PhotoDetails);
stack.Spacing(5);
stack.Item().Element(PhotoWithMaps);
stack.Item().Element(PhotoDetails);
});
}
@@ -31,14 +30,14 @@ namespace QuestPDF.ReportSample.Layouts
container
.Row(row =>
{
row.RelativeItem(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
row.RelativeColumn(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
row.RelativeItem().PaddingLeft(5).Column(column =>
row.RelativeColumn().PaddingLeft(5).Stack(stack =>
{
column.Spacing(7f);
stack.Spacing(7f);
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
});
});
}
@@ -48,7 +47,7 @@ namespace QuestPDF.ReportSample.Layouts
container.Border(0.75f).BorderColor(Colors.Grey.Medium).Grid(grid =>
{
grid.Columns(6);
grid.Item().LabelCell().Text("Date");
grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty);
grid.Item().LabelCell().Text("Location");
@@ -21,26 +21,25 @@ namespace QuestPDF.ReportSample.Layouts
.Decoration(decoration =>
{
decoration
.Before()
.Header()
.PaddingBottom(5)
.Text(Model.Title)
.Style(Typography.Headline);
.Text(Model.Title, Typography.Headline);
decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Column(column =>
decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack =>
{
foreach (var part in Model.Parts)
{
column.Item().EnsureSpace(25).Row(row =>
stack.Item().EnsureSpace(25).Row(row =>
{
row.ConstantItem(150).LabelCell().Text(part.Label);
var frame = row.RelativeItem().ValueCell();
row.ConstantColumn(150).LabelCell().Text(part.Label);
var frame = row.RelativeColumn().ValueCell();
if (part is ReportSectionText text)
frame.ShowEntire().Text(text.Text);
if (part is ReportSectionMap map)
frame.Element(x => MapElement(x, map));
if (part is ReportSectionPhotos photos)
frame.Element(x => PhotosElement(x, photos));
});
@@ -57,12 +56,12 @@ namespace QuestPDF.ReportSample.Layouts
return;
}
container.ShowEntire().Column(column =>
container.ShowEntire().Stack(stack =>
{
column.Spacing(5);
stack.Spacing(5);
column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
column.Item().Text(model.Location.Format());
stack.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
stack.Item().Text(model.Location.Format());
});
}
@@ -70,7 +69,7 @@ namespace QuestPDF.ReportSample.Layouts
{
if (model.PhotoCount == 0)
{
container.Text("No photos").Style(Typography.Normal);
container.Text("No photos", Typography.Normal);
return;
}
@@ -39,28 +39,28 @@ namespace QuestPDF.ReportSample.Layouts
page.Footer().AlignCenter().Text(text =>
{
text.CurrentPageNumber().Format(x => x?.FormatAsRomanNumeral() ?? "-----");
text.CurrentPageNumber();
text.Span(" / ");
text.TotalPages().Format(x => x?.FormatAsRomanNumeral() ?? "-----");
text.TotalPages();
});
});
}
private void ComposeHeader(IContainer container)
{
container.Column(column =>
container.Stack(stack =>
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.Spacing(50);
row.RelativeItem().PaddingTop(-10).Text(Model.Title).Style(Typography.Title);
row.ConstantItem(90).Hyperlink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
row.RelativeColumn().PaddingTop(-10).Text(Model.Title, Typography.Title);
row.ConstantColumn(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
});
column.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
stack.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
column.Item().ShowOnce().Grid(grid =>
stack.Item().ShowOnce().Grid(grid =>
{
grid.Columns(2);
grid.Spacing(5);
@@ -69,7 +69,7 @@ namespace QuestPDF.ReportSample.Layouts
{
grid.Item().Text(text =>
{
text.Span($"{field.Label}: ").SemiBold();
text.Span($"{field.Label}: ", TextStyle.Default.SemiBold());
text.Span(field.Value);
});
}
@@ -79,23 +79,23 @@ namespace QuestPDF.ReportSample.Layouts
void ComposeContent(IContainer container)
{
container.PaddingVertical(20).Column(column =>
container.PaddingVertical(20).Stack(stack =>
{
column.Spacing(20);
stack.Spacing(20);
stack.Item().Component(new TableOfContentsTemplate(Model.Sections));
column.Item().Component(new TableOfContentsTemplate(Model.Sections));
column.Item().PageBreak();
stack.Item().PageBreak();
foreach (var section in Model.Sections)
column.Item().Section(section.Title).Component(new SectionTemplate(section));
column.Item().PageBreak();
column.Item().Section("Photos");
stack.Item().Location(section.Title).Component(new SectionTemplate(section));
stack.Item().PageBreak();
stack.Item().Location("Photos");
foreach (var photo in Model.Photos)
column.Item().Component(new PhotoTemplate(photo));
stack.Item().Component(new PhotoTemplate(photo));
});
}
}
}
}
@@ -0,0 +1,50 @@
using System.Collections.Generic;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
namespace QuestPDF.ReportSample.Layouts
{
public class TableOfContentsTemplate : IComponent
{
private List<ReportSection> Sections { get; }
public TableOfContentsTemplate(List<ReportSection> sections)
{
Sections = sections;
}
public void Compose(IContainer container)
{
container
.Decoration(decoration =>
{
decoration
.Header()
.PaddingBottom(5)
.Text("Table of contents", Typography.Headline);
decoration.Content().Stack(stack =>
{
stack.Spacing(5);
for (var i = 0; i < Sections.Count; i++)
stack.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
stack.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
});
});
}
private void DrawLink(IContainer container, int number, string locationName)
{
container
.InternalLink(locationName)
.Row(row =>
{
row.ConstantColumn(25).Text($"{number}.");
row.RelativeColumn().Text(locationName);
row.ConstantColumn(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName));
});
}
}
}
+74
View File
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Running;
using Microsoft.VisualStudio.TestPlatform.TestHost;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Drawing.Proxy;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.ReportSample.Layouts;
namespace QuestPDF.ReportSample
{
[SimpleJob(RunStrategy.Monitoring, launchCount: 0, warmupCount: 1, targetCount: 256)]
[MinColumn, MaxColumn, MeanColumn, MedianColumn]
public class PerformanceTests
{
private PageContext PageContext { get; set; }
private DocumentMetadata Metadata { get; set; }
private Container Content { get; set; }
[Test]
public void Run()
{
ImagePlaceholder.Solid = true;
var configuration = ManualConfig
.Create(DefaultConfig.Instance)
.WithOptions(ConfigOptions.DisableOptimizationsValidator);
BenchmarkRunner.Run<PerformanceTests>(configuration);
}
[IterationSetup]
public void GenerateReportData()
{
ImagePlaceholder.Solid = true;
var model = DataSource.GetReport();
var report = new StandardReport(model);
Metadata = report.GetMetadata();
var documentContainer = new DocumentContainer();
report.Compose(documentContainer);
Content = documentContainer.Compose();
PageContext = new PageContext();
DocumentGenerator.RenderPass(PageContext, new FreeCanvas(), Content, Metadata, null);
var sw = new Stopwatch();
sw.Start();
Content.HandleVisitor(x =>
{
if (x is ICacheable)
x.CreateProxy(y => new CacheProxy(y));
});
sw.Stop();
Console.WriteLine($"Creating cache took: {sw.ElapsedMilliseconds}");
}
[Benchmark]
public void GenerationTest()
{
DocumentGenerator.RenderPass(PageContext, new FreeCanvas(), Content, Metadata, null);
}
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>8</LangVersion>
<RootNamespace>QuestPDF.ReportSample</RootNamespace>
@@ -10,9 +10,9 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="SkiaSharp" Version="2.88.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="SkiaSharp" Version="2.80.3" />
</ItemGroup>
<ItemGroup>

Before

Width:  |  Height:  |  Size: 993 B

After

Width:  |  Height:  |  Size: 993 B

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@@ -17,8 +17,6 @@ namespace QuestPDF.ReportSample
[SetUp]
public void SetUp()
{
QuestPDF.Settings.License = LicenseType.Community;
var model = DataSource.GetReport();
Report = new StandardReport(model);
}
@@ -26,8 +24,6 @@ namespace QuestPDF.ReportSample
[Test]
public void GenerateAndShowPdf()
{
//ImagePlaceholder.Solid = true;
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
Report.GeneratePdf(path);
Process.Start("explorer.exe", path);
@@ -40,5 +36,21 @@ namespace QuestPDF.ReportSample
Report.GenerateXps(path);
Process.Start("explorer.exe", path);
}
[Test]
public void Profile()
{
ImagePlaceholder.Solid = true;
var container = new DocumentContainer();
Report.Compose(container);
var content = container.Compose();
var metadata = Report.GetMetadata();
var pageContext = new PageContext();
DocumentGenerator.RenderPass(pageContext, new FreeCanvas(), content, metadata, null);
DocumentGenerator.RenderPass(pageContext, new FreeCanvas(), content, metadata, null);
}
}
}
@@ -6,8 +6,8 @@ namespace QuestPDF.ReportSample
{
public static class Typography
{
public static TextStyle Title => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Blue.Darken3).FontSize(26).Black();
public static TextStyle Headline => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Blue.Medium).FontSize(16).SemiBold();
public static TextStyle Normal => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Black).FontSize(10).LineHeight(1.2f);
public static TextStyle Title => TextStyle.Default.FontType(Fonts.Calibri).Color(Colors.Blue.Darken3).Size(26).Black();
public static TextStyle Headline => TextStyle.Default.FontType(Fonts.Calibri).Color(Colors.Blue.Medium).Size(16).SemiBold();
public static TextStyle Normal => TextStyle.Default.FontType(Fonts.Verdana).Color(Colors.Black).Size(10).LineHeight(1.2f);
}
}
}
@@ -86,43 +86,5 @@ namespace QuestPDF.UnitTests
.ExpectCanvasTranslate(new Position(-300, 0))
.CheckDrawResult();
}
[Test]
public void Draw_HorizontalCenter_VerticalNone()
{
TestPlan
.For(x => new Alignment
{
Horizontal = HorizontalAlignment.Center,
Vertical = null,
Child = x.CreateChild()
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
.ExpectCanvasTranslate(new Position(150, 0))
.ExpectChildDraw(new Size(100, 300))
.ExpectCanvasTranslate(new Position(-150, 0))
.CheckDrawResult();
}
[Test]
public void Draw_HorizontalNone_VerticalMiddle()
{
TestPlan
.For(x => new Alignment
{
Horizontal = null,
Vertical = VerticalAlignment.Middle,
Child = x.CreateChild()
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
.ExpectCanvasTranslate(new Position(0, 125))
.ExpectChildDraw(new Size(400, 50))
.ExpectCanvasTranslate(new Position(0, -125))
.CheckDrawResult();
}
}
}
@@ -153,9 +153,7 @@ namespace QuestPDF.UnitTests
Ratio = 2f
})
.DrawElement(new Size(500, 200))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw(new Size(400, 200))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
@@ -170,45 +168,7 @@ namespace QuestPDF.UnitTests
Ratio = 2f
})
.DrawElement(new Size(400, 300))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw(new Size(400, 200))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
[Test]
public void DrawChild_PerWidth_RightToLeft()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f,
ContentDirection = ContentDirection.RightToLeft
})
.DrawElement(new Size(500, 200))
.ExpectCanvasTranslate(100, 0)
.ExpectChildDraw(new Size(400, 200))
.ExpectCanvasTranslate(-100, 0)
.CheckDrawResult();
}
[Test]
public void DrawChild_PerHeight_RightToLeft()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f,
ContentDirection = ContentDirection.RightToLeft
})
.DrawElement(new Size(400, 300))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw(new Size(400, 200))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
}
@@ -21,7 +21,7 @@ namespace QuestPDF.UnitTests
Color = Colors.Red.Medium
})
.DrawElement(new Size(400, 300))
.ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), Colors.Red.Medium)
.ExpectCanvasDrawFilledRectangle(new Position(0, 0), new Size(400, 300), Colors.Red.Medium)
.CheckDrawResult();
}
@@ -35,7 +35,7 @@ namespace QuestPDF.UnitTests
Child = x.CreateChild()
})
.DrawElement(new Size(400, 300))
.ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), Colors.Red.Medium)
.ExpectCanvasDrawFilledRectangle(new Position(0, 0), new Size(400, 300), Colors.Red.Medium)
.ExpectChildDraw(new Size(400, 300))
.CheckDrawResult();
}
@@ -1,9 +1,11 @@
using NUnit.Framework;
using System.Drawing;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
using Size = QuestPDF.Infrastructure.Size;
namespace QuestPDF.UnitTests
{
@@ -32,7 +34,29 @@ namespace QuestPDF.UnitTests
}
[Test]
public void Draw_HorizontalRight_VerticalTop()
public void Draw_SameWidths_Optimized()
{
TestPlan
.For(x => new Border
{
Top = 10,
Right = 10,
Bottom = 10,
Left = 10,
Color = Colors.Red.Medium,
Child = x.CreateChild()
})
.DrawElement(new Size(400, 300))
.ExpectChildDraw(new Size(400, 300))
.ExpectCanvasDrawStrokedRectangle(new Size(400, 300), Colors.Red.Medium, 10)
.ExpectChildDraw(new Size(400, 300))
.CheckDrawResult();
}
[Test]
public void Draw_VariousWidths()
{
TestPlan
.For(x => new Border
@@ -48,10 +72,10 @@ namespace QuestPDF.UnitTests
})
.DrawElement(new Size(400, 300))
.ExpectChildDraw(new Size(400, 300))
.ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(430, 10), Colors.Red.Medium) // top
.ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(40, 320), Colors.Red.Medium) // left
.ExpectCanvasDrawRectangle(new Position(-20, 285), new Size(430, 30), Colors.Red.Medium) // bottom
.ExpectCanvasDrawRectangle(new Position(390, -5), new Size(20, 320), Colors.Red.Medium) // right
.ExpectCanvasDrawFilledRectangle(new Position(-20, -5), new Size(430, 10), Colors.Red.Medium) // top
.ExpectCanvasDrawFilledRectangle(new Position(-20, -5), new Size(40, 320), Colors.Red.Medium) // left
.ExpectCanvasDrawFilledRectangle(new Position(-20, 285), new Size(430, 30), Colors.Red.Medium) // bottom
.ExpectCanvasDrawFilledRectangle(new Position(390, -5), new Size(20, 320), Colors.Red.Medium) // right
.ExpectChildDraw(new Size(400, 300))
.CheckDrawResult();
}
+56
View File
@@ -0,0 +1,56 @@
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class BoxTests
{
[Test]
public void Measure() => SimpleContainerTests.Measure<Box>();
[Test]
public void Draw_Wrap()
{
TestPlan
.For(x => new Box
{
Child = x.CreateChild()
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.Wrap())
.CheckDrawResult();
}
[Test]
public void Measure_PartialRender()
{
TestPlan
.For(x => new Box
{
Child = x.CreateChild()
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.PartialRender(200, 100))
.ExpectChildDraw(new Size(200, 100))
.CheckDrawResult();
}
[Test]
public void Measure_FullRender()
{
TestPlan
.For(x => new Box
{
Child = x.CreateChild()
})
.MeasureElement(new Size(500, 400))
.ExpectChildMeasure(expectedInput: new Size(500, 400), returns: SpacePlan.FullRender(300, 200))
.ExpectChildDraw(new Size(300, 200))
.CheckDrawResult();
}
}
}
+136
View File
@@ -0,0 +1,136 @@
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class DecorationTests
{
#region Measure
[Test]
public void Measure_ReturnsWrap_WhenDecorationReturnsWrap()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.Wrap())
.CheckMeasureResult(SpacePlan.Wrap());
}
[Test]
public void Measure_ReturnsWrap_WhenDecorationReturnsPartialRender()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.PartialRender(300, 200))
.CheckMeasureResult(SpacePlan.Wrap());
}
[Test]
public void Measure_ReturnsWrap_WhenContentReturnsWrap()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.Wrap())
.CheckMeasureResult(SpacePlan.Wrap());
}
[Test]
public void Measure_ReturnsPartialRender_WhenContentReturnsPartialRender()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(200, 150))
.CheckMeasureResult(SpacePlan.PartialRender(400, 250));
}
[Test]
public void Measure_ReturnsFullRender_WhenContentReturnsFullRender()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(200, 150))
.CheckMeasureResult(SpacePlan.FullRender(400, 250));
}
#endregion
#region Draw
[Test]
public void Draw_Prepend()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Prepend,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
.ExpectChildDraw("decoration", new Size(400, 100))
.ExpectCanvasTranslate(0, 100)
.ExpectChildDraw("content", new Size(400, 200))
.ExpectCanvasTranslate(0, -100)
.CheckDrawResult();
}
[Test]
public void Draw_Append()
{
TestPlan
.For(x => new BinaryDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
.ExpectChildDraw("content", new Size(400, 200))
.ExpectCanvasTranslate(0, 200)
.ExpectChildDraw("decoration", new Size(400, 100))
.ExpectCanvasTranslate(0, -200)
.CheckDrawResult();
}
#endregion
}
}
@@ -8,7 +8,7 @@ namespace QuestPDF.UnitTests
public class ExternalLinkTests
{
[Test]
public void Measure() => SimpleContainerTests.Measure<Hyperlink>();
public void Measure() => SimpleContainerTests.Measure<ExternalLink>();
// TODO: consider tests for the Draw method
}
@@ -39,26 +39,26 @@ namespace QuestPDF.UnitTests
// assert
var expected = new Container();
expected.Column(column =>
expected.Stack(stack =>
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(6).Element(childA);
row.RelativeItem(4).Element(childB);
row.RelativeItem(2);
row.RelativeColumn(6).Element(childA);
row.RelativeColumn(4).Element(childB);
row.RelativeColumn(2);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(4).Element(childC);
row.RelativeItem(2).Element(childD);
row.RelativeItem(6);
row.RelativeColumn(4).Element(childC);
row.RelativeColumn(2).Element(childD);
row.RelativeColumn(6);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(8).Element(childE);
row.RelativeItem(4);
row.RelativeColumn(8).Element(childE);
row.RelativeColumn(4);
});
});
@@ -93,29 +93,29 @@ namespace QuestPDF.UnitTests
// assert
var expected = new Container();
expected.Column(column =>
expected.Stack(stack =>
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(1);
row.RelativeItem(6).Element(childA);
row.RelativeItem(4).Element(childB);
row.RelativeItem(1);
row.RelativeColumn(1);
row.RelativeColumn(6).Element(childA);
row.RelativeColumn(4).Element(childB);
row.RelativeColumn(1);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(3);
row.RelativeItem(4).Element(childC);
row.RelativeItem(2).Element(childD);
row.RelativeItem(3);
row.RelativeColumn(3);
row.RelativeColumn(4).Element(childC);
row.RelativeColumn(2).Element(childD);
row.RelativeColumn(3);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(2);
row.RelativeItem(8).Element(childE);
row.RelativeItem(2);
row.RelativeColumn(2);
row.RelativeColumn(8).Element(childE);
row.RelativeColumn(2);
});
});
@@ -150,26 +150,26 @@ namespace QuestPDF.UnitTests
// assert
var expected = new Container();
expected.Column(column =>
expected.Stack(stack =>
{
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(2);
row.RelativeItem(6).Element(childA);
row.RelativeItem(4).Element(childB);
row.RelativeColumn(2);
row.RelativeColumn(6).Element(childA);
row.RelativeColumn(4).Element(childB);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(6);
row.RelativeItem(4).Element(childC);
row.RelativeItem(2).Element(childD);
row.RelativeColumn(6);
row.RelativeColumn(4).Element(childC);
row.RelativeColumn(2).Element(childD);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.RelativeItem(4);
row.RelativeItem(8).Element(childE);
row.RelativeColumn(4);
row.RelativeColumn(8).Element(childE);
});
});
@@ -210,36 +210,36 @@ namespace QuestPDF.UnitTests
// assert
var expected = new Container();
expected.Column(column =>
expected.Stack(stack =>
{
column.Spacing(20);
stack.Spacing(20);
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.Spacing(30);
row.RelativeItem(3);
row.RelativeItem(5).Element(childA);
row.RelativeItem(5).Element(childB);
row.RelativeItem(3);
row.RelativeColumn(3);
row.RelativeColumn(5).Element(childA);
row.RelativeColumn(5).Element(childB);
row.RelativeColumn(3);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.Spacing(30);
row.RelativeItem(3);
row.RelativeItem(10).Element(childC);
row.RelativeItem(3);
row.RelativeColumn(3);
row.RelativeColumn(10).Element(childC);
row.RelativeColumn(3);
});
column.Item().Row(row =>
stack.Item().Row(row =>
{
row.Spacing(30);
row.RelativeItem(2);
row.RelativeItem(12).Element(childD);
row.RelativeItem(2);
row.RelativeColumn(2);
row.RelativeColumn(12).Element(childD);
row.RelativeColumn(2);
});
});
@@ -8,7 +8,7 @@ namespace QuestPDF.UnitTests
public class InternalLinkTests
{
[Test]
public void Measure() => SimpleContainerTests.Measure<SectionLink>();
public void Measure() => SimpleContainerTests.Measure<InternalLink>();
// TODO: consider tests for the Draw method
}
@@ -8,7 +8,7 @@ namespace QuestPDF.UnitTests
public class InternalLocationTests
{
[Test]
public void Measure() => SimpleContainerTests.Measure<SectionLink>();
public void Measure() => SimpleContainerTests.Measure<InternalLink>();
// TODO: consider tests for the Draw method
}
@@ -3,28 +3,18 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="FluentAssertions" Version="6.1.0" />
<PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="SkiaSharp" Version="2.88.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="SkiaSharp" Version="2.80.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\FontContent.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="Resources\FontEmbeddedResource.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
</Project>
+267
View File
@@ -0,0 +1,267 @@
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class RowTests
{
#region Measure
[Test]
public void Measure_ReturnsWrap_WhenLeftChildReturnsWrap()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.Wrap())
.CheckMeasureResult(SpacePlan.Wrap());
}
[Test]
public void Measure_ReturnsWrap_WhenRightChildReturnsWrap()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), SpacePlan.Wrap())
.CheckMeasureResult(SpacePlan.Wrap());
}
[Test]
public void Measure_ReturnsPartialRender_WhenLeftChildReturnsPartialRender()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.PartialRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(100, 100))
.CheckMeasureResult(SpacePlan.PartialRender(350, 150));
}
[Test]
public void Measure_ReturnsPartialRender_WhenRightChildReturnsPartialRender()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), SpacePlan.PartialRender(100, 100))
.CheckMeasureResult(SpacePlan.PartialRender(350, 150));
}
[Test]
public void Measure_ReturnsFullRender_WhenBothChildrenReturnFullRender()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(200, 150))
.ExpectChildMeasure("right", new Size(200, 300), SpacePlan.FullRender(100, 100))
.CheckMeasureResult(SpacePlan.FullRender(300, 150));
}
#endregion
#region Draw
[Test]
public void Draw()
{
TestPlan
.For(x => new BinaryRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
.ExpectChildDraw("left", new Size(250, 300))
.ExpectCanvasTranslate(250, 0)
.ExpectChildDraw("right", new Size(150, 300))
.ExpectCanvasTranslate(-250, 0)
.CheckDrawResult();
}
#endregion
#region Structure
[Test]
public void Structure_RelativeColumnsHandling()
{
// arrange
var childA = TestPlan.CreateUniqueElement();
var childB = TestPlan.CreateUniqueElement();
var childC = TestPlan.CreateUniqueElement();
var childD = TestPlan.CreateUniqueElement();
var childE = TestPlan.CreateUniqueElement();
const int spacing = 25;
var availableSpace = new Size(1100, 400);
// act
var value = new Container();
value.Row(row =>
{
row.Spacing(spacing);
row.ConstantColumn(150).Element(childA);
row.ConstantColumn(250).Element(childB);
row.RelativeColumn(1).Element(childC);
row.RelativeColumn(2).Element(childD);
row.RelativeColumn(3).Element(childE);
});
// assert
var expected = new Container();
expected.Row(row =>
{
row.Spacing(spacing);
row.ConstantColumn(150).Element(childA);
row.ConstantColumn(250).Element(childB);
row.ConstantColumn(100).Element(childC);
row.ConstantColumn(200).Element(childD);
row.ConstantColumn(300).Element(childE);
});
TestPlan.CompareOperations(value, expected, availableSpace);
}
[Test]
public void Structure_Tree()
{
// arrange
var childA = TestPlan.CreateUniqueElement();
var childB = TestPlan.CreateUniqueElement();
var childC = TestPlan.CreateUniqueElement();
var childD = TestPlan.CreateUniqueElement();
var childE = TestPlan.CreateUniqueElement();
const int spacing = 25;
var availableSpace = new Size(1200, 400);
// act
var value = new Container();
value.Row(row =>
{
row.Spacing(spacing);
row.ConstantColumn(150).Element(childA);
row.ConstantColumn(200).Element(childB);
row.ConstantColumn(250).Element(childC);
row.RelativeColumn(2).Element(childD);
row.RelativeColumn(3).Element(childE);
});
// assert
var expected = new BinaryRow
{
Left = new BinaryRow
{
Left = new BinaryRow
{
Left = new Constrained
{
MinWidth = 150,
MaxWidth = 150,
Child = childA
},
Right = new Constrained
{
MinWidth = 25,
MaxWidth = 25
}
},
Right = new BinaryRow
{
Left = new Constrained
{
MinWidth = 200,
MaxWidth = 200,
Child = childB
},
Right = new Constrained
{
MinWidth = 25,
MaxWidth = 25
}
}
},
Right = new BinaryRow
{
Left = new BinaryRow
{
Left = new Constrained
{
MinWidth = 250,
MaxWidth = 250,
Child = childC
},
Right = new Constrained
{
MinWidth = 25,
MaxWidth = 25
}
},
Right = new BinaryRow
{
Left = new Constrained
{
MinWidth = 200,
MaxWidth = 200,
Child = childD
},
Right = new BinaryRow
{
Left = new Constrained
{
MinWidth = 25,
MaxWidth = 25
},
Right = new Constrained
{
MinWidth = 300,
MaxWidth = 300,
Child = childE
}
}
}
}
};
TestPlan.CompareOperations(value, expected, availableSpace);
}
#endregion
}
}
@@ -1,5 +1,4 @@
using System.Linq;
using NUnit.Framework;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
@@ -9,40 +8,19 @@ using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class ColumnTests
public class StackTests
{
private Column CreateColumnWithTwoItems(TestPlan testPlan)
{
return new Column
{
Items =
{
new ColumnItem
{
Child = testPlan.CreateChild("first")
},
new ColumnItem
{
Child = testPlan.CreateChild("second")
}
}
};
}
private Column CreateColumnWithTwoItemsWhereFirstIsFullyRendered(TestPlan testPlan)
{
var column = CreateColumnWithTwoItems(testPlan);
column.Items.First().IsRendered = true;
return column;
}
#region Measure
[Test]
public void Measure_ReturnsWrap_WhenFirstChildWraps()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
.CheckMeasureResult(SpacePlan.Wrap());
@@ -52,7 +30,11 @@ namespace QuestPDF.UnitTests
public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(300, 200))
.CheckMeasureResult(SpacePlan.PartialRender(300, 200));
@@ -62,7 +44,11 @@ namespace QuestPDF.UnitTests
public void Measure_ReturnsPartialRender_WhenSecondChildWraps()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
@@ -73,7 +59,11 @@ namespace QuestPDF.UnitTests
public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(300, 150))
@@ -84,13 +74,33 @@ namespace QuestPDF.UnitTests
public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(100, 50))
.CheckMeasureResult(SpacePlan.FullRender(200, 150));
}
[Test]
public void Measure_UsesEmpty_WhenFirstChildIsRendered()
{
TestPlan
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second"),
IsFirstRendered = true
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300))
.CheckMeasureResult(SpacePlan.FullRender(200, 300));
}
#endregion
#region Draw
@@ -99,7 +109,11 @@ namespace QuestPDF.UnitTests
public void Draw_WhenFirstChildWraps()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
.CheckDrawResult();
@@ -109,12 +123,14 @@ namespace QuestPDF.UnitTests
public void Draw_WhenFirstChildPartiallyRenders()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(200, 100))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("first", new Size(400, 100))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
@@ -122,13 +138,15 @@ namespace QuestPDF.UnitTests
public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("first", new Size(400, 100))
.ExpectCanvasTranslate(0, 0)
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
.CheckDrawResult();
}
@@ -136,13 +154,15 @@ namespace QuestPDF.UnitTests
public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(250, 150))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("first", new Size(400, 100))
.ExpectCanvasTranslate(0, 0)
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(250, 150))
.ExpectCanvasTranslate(0, 100)
.ExpectChildDraw("second", new Size(400, 150))
.ExpectCanvasTranslate(0, -100)
@@ -153,13 +173,15 @@ namespace QuestPDF.UnitTests
public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()
{
TestPlan
.For(CreateColumnWithTwoItems)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(250, 150))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("first", new Size(400, 100))
.ExpectCanvasTranslate(0, 0)
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(250, 150))
.ExpectCanvasTranslate(0, 100)
.ExpectChildDraw("second", new Size(400, 150))
.ExpectCanvasTranslate(0, -100)
@@ -170,13 +192,19 @@ namespace QuestPDF.UnitTests
public void Draw_UsesEmpty_WhenFirstChildIsRendered()
{
TestPlan
.For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second"),
IsFirstRendered = true
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("second", new Size(400, 300), SpacePlan.PartialRender(200, 300))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("second", new Size(400, 300))
.ExpectCanvasTranslate(0, 0)
.CheckState<Column>(x => x.Items.First().IsRendered)
.CheckState<BinaryStack>(x => x.IsFirstRendered)
.CheckDrawResult();
}
@@ -184,14 +212,97 @@ namespace QuestPDF.UnitTests
public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
{
TestPlan
.For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
.For(x => new BinaryStack
{
First = x.CreateChild("first"),
Second = x.CreateChild("second"),
IsFirstRendered = true
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw("second", new Size(400, 300))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult()
.CheckState<Column>(x => !x.Items.First().IsRendered);
.CheckState<BinaryStack>(x => !x.IsFirstRendered);
}
#endregion
#region Structure
[Test]
public void Structure_Simple()
{
// arrange
var childA = TestPlan.CreateUniqueElement();
var childB = TestPlan.CreateUniqueElement();
var childC = TestPlan.CreateUniqueElement();
var childD = TestPlan.CreateUniqueElement();
var childE = TestPlan.CreateUniqueElement();
const int spacing = 20;
// act
var structure = new Container();
structure.Stack(stack =>
{
stack.Spacing(spacing);
stack.Item().Element(childA);
stack.Item().Element(childB);
stack.Item().Element(childC);
stack.Item().Element(childD);
stack.Item().Element(childE);
});
// assert
var expected = new Padding
{
Bottom = -spacing,
Child = new BinaryStack
{
First = new BinaryStack
{
First = new Padding
{
Bottom = spacing,
Child = childA
},
Second = new Padding
{
Bottom = spacing,
Child = childB
}
},
Second = new BinaryStack
{
First = new Padding
{
Bottom = spacing,
Child = childC
},
Second = new BinaryStack
{
First = new Padding
{
Bottom = spacing,
Child = childD
},
Second = new Padding
{
Bottom = spacing,
Child = childE
}
}
}
}
};
TestPlan.CompareOperations(structure, expected);
}
#endregion
@@ -0,0 +1,30 @@
using System;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.UnitTests.TestEngine
{
internal class MockCanvas : ICanvas
{
public Action<Position> TranslateFunc { get; set; }
public Action<float> RotateFunc { get; set; }
public Action<float, float> ScaleFunc { get; set; }
public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
public Action<Position, Size, string> DrawFilledRectangleFunc { get; set; }
public Action<Size, string, float> DrawStrokedRectangleFunc { get; set; }
public void Translate(Position vector) => TranslateFunc(vector);
public void Rotate(float angle) => RotateFunc(angle);
public void Scale(float scaleX, float scaleY) => ScaleFunc(scaleX, scaleY);
public void DrawFilledRectangle(Position vector, Size size, string color) => DrawFilledRectangleFunc(vector, size, color);
public void DrawStrokedRectangle(Size size, string color, float width) => DrawStrokedRectangleFunc(size, color, width);
public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
public void DrawExternalLink(string url, Size size) => throw new NotImplementedException();
public void DrawLocationLink(string locationName, Size size) => throw new NotImplementedException();
public void DrawLocation(string locationName) => throw new NotImplementedException();
}
}
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using QuestPDF.Drawing;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine.Operations;
using SkiaSharp;
@@ -15,12 +14,13 @@ namespace QuestPDF.UnitTests.TestEngine
public void Rotate(float angle) => Operations.Add(new CanvasRotateOperation(angle));
public void Scale(float scaleX, float scaleY) => Operations.Add(new CanvasScaleOperation(scaleX, scaleY));
public void DrawRectangle(Position vector, Size size, string color) => Operations.Add(new CanvasDrawRectangleOperation(vector, size, color));
public void DrawText(SKTextBlob skTextBlob, Position position, TextStyle style) => throw new NotImplementedException();
public void DrawFilledRectangle(Position vector, Size size, string color) => Operations.Add(new CanvasDrawFilledRectangleOperation(vector, size, color));
public void DrawStrokedRectangle(Size size, string color, float width) => Operations.Add(new CanvasDrawStrokedRectangleOperation(size, color, width));
public void DrawText(string text, Position position, TextStyle style) => Operations.Add(new CanvasDrawTextOperation(text, position, style));
public void DrawImage(SKImage image, Position position, Size size) => Operations.Add(new CanvasDrawImageOperation(position, size));
public void DrawHyperlink(string url, Size size) => throw new NotImplementedException();
public void DrawSectionLink(string sectionName, Size size) => throw new NotImplementedException();
public void DrawSection(string sectionName) => throw new NotImplementedException();
public void DrawExternalLink(string url, Size size) => throw new NotImplementedException();
public void DrawLocationLink(string locationName, Size size) => throw new NotImplementedException();
public void DrawLocation(string locationName) => throw new NotImplementedException();
}
}
@@ -2,13 +2,13 @@
namespace QuestPDF.UnitTests.TestEngine.Operations
{
internal class CanvasDrawRectangleOperation : OperationBase
internal class CanvasDrawFilledRectangleOperation : OperationBase
{
public Position Position { get; }
public Size Size { get; }
public string Color { get; }
public CanvasDrawRectangleOperation(Position position, Size size, string color)
public CanvasDrawFilledRectangleOperation(Position position, Size size, string color)
{
Position = position;
Size = size;
@@ -0,0 +1,18 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.UnitTests.TestEngine.Operations
{
internal class CanvasDrawStrokedRectangleOperation : OperationBase
{
public Size Size { get; }
public string Color { get; }
public float Width { get; set; }
public CanvasDrawStrokedRectangleOperation(Size size, string color, float width)
{
Size = size;
Color = color;
Width = width;
}
}
}
@@ -70,17 +70,40 @@ namespace QuestPDF.UnitTests.TestEngine
Assert.AreEqual(expected.ScaleX, scaleX, "Scale X");
Assert.AreEqual(expected.ScaleY, scaleY, "Scale Y");
},
DrawRectFunc = (position, size, color) =>
DrawFilledRectangleFunc = (position, size, color) =>
{
var expected = GetExpected<CanvasDrawRectangleOperation>();
var expected = GetExpected<CanvasDrawFilledRectangleOperation>();
Assert.AreEqual(expected.Position.X, position.X, "Draw rectangle: X");
Assert.AreEqual(expected.Position.Y, position.Y, "Draw rectangle: Y");
Assert.AreEqual(expected.Position.X, position.X, "Draw filled rectangle: X");
Assert.AreEqual(expected.Position.Y, position.Y, "Draw filled rectangle: Y");
Assert.AreEqual(expected.Size.Width, size.Width, "Draw rectangle: width");
Assert.AreEqual(expected.Size.Height, size.Height, "Draw rectangle: height");
Assert.AreEqual(expected.Size.Width, size.Width, "Draw filled rectangle: width");
Assert.AreEqual(expected.Size.Height, size.Height, "Draw filled rectangle: height");
Assert.AreEqual(expected.Color, color, "Draw rectangle: color");
Assert.AreEqual(expected.Color, color, "Draw filled rectangle: color");
},
DrawStrokedRectangleFunc = (size, color, width) =>
{
var expected = GetExpected<CanvasDrawStrokedRectangleOperation>();
Assert.AreEqual(expected.Size.Width, size.Width, "Draw stroked rectangle: width");
Assert.AreEqual(expected.Size.Height, size.Height, "Draw stroked rectangle: height");
Assert.AreEqual(expected.Color, color, "Draw stroked rectangle: color");
Assert.AreEqual(expected.Width, width, "Draw stroked rectangle: width");
},
DrawTextFunc = (text, position, style) =>
{
var expected = GetExpected<CanvasDrawTextOperation>();
Assert.AreEqual(expected.Text, text);
Assert.AreEqual(expected.Position.X, position.X, "Draw text: X");
Assert.AreEqual(expected.Position.Y, position.Y, "Draw text: Y");
Assert.AreEqual(expected.Style.Color, style.Color, "Draw text: color");
Assert.AreEqual(expected.Style.FontType, style.FontType, "Draw text: font");
Assert.AreEqual(expected.Style.Size, style.Size, "Draw text: size");
},
DrawImageFunc = (image, position, size) =>
{
@@ -183,9 +206,19 @@ namespace QuestPDF.UnitTests.TestEngine
return AddOperation(new CanvasRotateOperation(angle));
}
public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, string color)
public TestPlan ExpectCanvasDrawFilledRectangle(Position position, Size size, string color)
{
return AddOperation(new CanvasDrawRectangleOperation(position, size, color));
return AddOperation(new CanvasDrawFilledRectangleOperation(position, size, color));
}
public TestPlan ExpectCanvasDrawStrokedRectangle(Size size, string color, float width)
{
return AddOperation(new CanvasDrawStrokedRectangleOperation(size, color, width));
}
public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
{
return AddOperation(new CanvasDrawTextOperation(text, position, style));
}
public TestPlan ExpectCanvasDrawImage(Position position, Size size)
@@ -195,7 +228,7 @@ namespace QuestPDF.UnitTests.TestEngine
public TestPlan CheckMeasureResult(SpacePlan expected)
{
Element.InjectDependencies(null, Canvas);
Element.HandleVisitor(x => x?.Initialize(null, Canvas));
var actual = Element.Measure(OperationInput);
@@ -210,7 +243,7 @@ namespace QuestPDF.UnitTests.TestEngine
public TestPlan CheckDrawResult()
{
Element.InjectDependencies(null, Canvas);
Element.HandleVisitor(x => x?.Initialize(null, Canvas));
Element.Draw(OperationInput);
return this;
}
@@ -253,10 +286,10 @@ namespace QuestPDF.UnitTests.TestEngine
availableSpace ??= new Size(400, 300);
var canvas = new FreeCanvas();
value.InjectDependencies(null, canvas);
value.HandleVisitor(x => x.Initialize(null, canvas));
var valueMeasure = value.Measure(availableSpace.Value);
expected.InjectDependencies(null, canvas);
expected.HandleVisitor(x => x.Initialize(null, canvas));
var expectedMeasure = expected.Measure(availableSpace.Value);
valueMeasure.Should().BeEquivalentTo(expectedMeasure);
@@ -267,11 +300,11 @@ namespace QuestPDF.UnitTests.TestEngine
availableSpace ??= new Size(400, 300);
var valueCanvas = new OperationRecordingCanvas();
value.InjectDependencies(null, valueCanvas);
value.HandleVisitor(x => x.Initialize(null, valueCanvas));
value.Draw(availableSpace.Value);
var expectedCanvas = new OperationRecordingCanvas();
expected.InjectDependencies(null, expectedCanvas);
expected.HandleVisitor(x => x.Initialize(null, expectedCanvas));
expected.Draw(availableSpace.Value);
valueCanvas.Operations.Should().BeEquivalentTo(expectedCanvas.Operations);
@@ -77,9 +77,7 @@ namespace QuestPDF.UnitTests
})
.DrawElement(new Size(900, 800))
.ExpectChildMeasure(Size.Max, SpacePlan.PartialRender(1200, 1600))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw(new Size(1200, 1600))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
@@ -93,43 +91,7 @@ namespace QuestPDF.UnitTests
})
.DrawElement(new Size(900, 800))
.ExpectChildMeasure(Size.Max, SpacePlan.FullRender(1600, 1000))
.ExpectCanvasTranslate(0, 0)
.ExpectChildDraw(new Size(1600, 1000))
.ExpectCanvasTranslate(0, 0)
.CheckDrawResult();
}
[Test]
public void Draw_WhenChildPartiallyRenders_RightToLeft()
{
TestPlan
.For(x => new Unconstrained
{
Child = x.CreateChild(),
ContentDirection = ContentDirection.RightToLeft
})
.DrawElement(new Size(900, 800))
.ExpectChildMeasure(Size.Max, SpacePlan.PartialRender(1200, 1600))
.ExpectCanvasTranslate(-1200, 0)
.ExpectChildDraw(new Size(1200, 1600))
.ExpectCanvasTranslate(1200, 0)
.CheckDrawResult();
}
[Test]
public void Draw_WhenChildFullyRenders_RightToLeft()
{
TestPlan
.For(x => new Unconstrained
{
Child = x.CreateChild(),
ContentDirection = ContentDirection.RightToLeft
})
.DrawElement(new Size(900, 800))
.ExpectChildMeasure(Size.Max, SpacePlan.FullRender(1600, 1000))
.ExpectCanvasTranslate(-1600, 0)
.ExpectChildDraw(new Size(1600, 1000))
.ExpectCanvasTranslate(1600, 0)
.CheckDrawResult();
}
-17
View File
@@ -8,15 +8,6 @@ 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.Examples", "QuestPDF.Previewer.Examples\QuestPDF.Previewer.Examples.csproj", "{CA413A39-038F-4A9F-B56F-0E5413B6B158}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Configuration", "Configuration", "{73123649-216A-47B4-BFB2-DADF13FBE75D}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPDF.Previewer", "QuestPDF.Previewer\QuestPDF.Previewer.csproj", "{B2FF6003-3A45-4A78-A85D-B86C7F01D054}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,13 +30,5 @@ 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
{CA413A39-038F-4A9F-B56F-0E5413B6B158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA413A39-038F-4A9F-B56F-0E5413B6B158}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA413A39-038F-4A9F-B56F-0E5413B6B158}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA413A39-038F-4A9F-B56F-0E5413B6B158}.Release|Any CPU.Build.0 = Release|Any CPU
{B2FF6003-3A45-4A78-A85D-B86C7F01D054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2FF6003-3A45-4A78-A85D-B86C7F01D054}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2FF6003-3A45-4A78-A85D-B86C7F01D054}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2FF6003-3A45-4A78-A85D-B86C7F01D054}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+6
View File
@@ -0,0 +1,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("QuestPDF.UnitTests")]
[assembly: InternalsVisibleTo("QuestPDF.Examples")]
[assembly: InternalsVisibleTo("QuestPDF.ReportSample")]
@@ -16,13 +16,13 @@ namespace QuestPDF.Drawing
var container = new Container();
container
.Column(column =>
.Stack(stack =>
{
Pages
.SelectMany(x => new List<Action>()
{
() => column.Item().PageBreak(),
() => column.Item().Component(x)
() => stack.Item().PageBreak(),
() => stack.Item().Component(x)
})
.Skip(1)
.ToList()
+166
View File
@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Drawing.Proxy;
using QuestPDF.Elements;
using QuestPDF.Elements.Text;
using QuestPDF.Elements.Text.Items;
using QuestPDF.Infrastructure;
namespace QuestPDF.Drawing
{
static class DocumentGenerator
{
internal static void GeneratePdf(Stream stream, IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new PdfCanvas(stream, metadata);
RenderDocument(canvas, document);
}
internal static void GenerateXps(Stream stream, IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new XpsCanvas(stream, metadata);
RenderDocument(canvas, document);
}
internal static ICollection<byte[]> GenerateImages(IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new ImageCanvas(metadata);
RenderDocument(canvas, document);
return canvas.Images;
}
private static void RenderDocument<TCanvas>(TCanvas canvas, IDocument document)
where TCanvas : ICanvas, IRenderingCanvas
{
var container = new DocumentContainer();
document.Compose(container);
var content = container.Compose();
var metadata = document.GetMetadata();
var pageContext = new PageContext();
var debuggingState = metadata.ApplyDebugging ? ApplyDebugging(content) : null;
if (metadata.ApplyCaching)
ApplyCaching(content);
RenderPass(pageContext, new FreeCanvas(), content, metadata, debuggingState);
RenderPass(pageContext, canvas, content, metadata, debuggingState);
}
internal static void RenderPass<TCanvas>(PageContext pageContext, TCanvas canvas, Container content, DocumentMetadata documentMetadata, DebuggingState? debuggingState)
where TCanvas : ICanvas, IRenderingCanvas
{
content.HandleVisitor(x => x?.Initialize(pageContext, canvas));
content.HandleVisitor(x => (x as IStateResettable)?.ResetState());
canvas.BeginDocument();
var currentPage = 1;
while(true)
{
pageContext.SetPageNumber(currentPage);
debuggingState?.Reset();
var spacePlan = content.Measure(Size.Max);
if (spacePlan.Type == SpacePlanType.Wrap)
{
canvas.EndDocument();
ThrowLayoutException();
}
try
{
canvas.BeginPage(spacePlan);
content.Draw(spacePlan);
}
catch (Exception exception)
{
canvas.EndDocument();
throw new DocumentDrawingException("An exception occured during document drawing.", exception);
}
canvas.EndPage();
if (currentPage >= documentMetadata.DocumentLayoutExceptionThreshold)
{
canvas.EndDocument();
ThrowLayoutException();
}
if (spacePlan.Type == SpacePlanType.FullRender)
break;
currentPage++;
}
canvas.EndDocument();
void ThrowLayoutException()
{
var message = $"Composed layout generates infinite document. This may happen in two cases. " +
$"1) Your document and its layout configuration is correct but the content takes more than {documentMetadata.DocumentLayoutExceptionThreshold} pages. " +
$"In this case, please increase the value {nameof(DocumentMetadata)}.{nameof(DocumentMetadata.DocumentLayoutExceptionThreshold)} property configured in the {nameof(IDocument.GetMetadata)} method. " +
$"2) The layout configuration of your document is invalid. Some of the elements require more space than is provided." +
$"Please analyze your documents structure to detect this element and fix its size constraints.";
throw new DocumentLayoutException(message)
{
ElementTrace = debuggingState?.BuildTrace() ?? "Debug trace is available only in the DEBUG mode."
};
}
}
private static void ApplyCaching(Container content)
{
content.HandleVisitor(x =>
{
if (x is ICacheable)
x.CreateProxy(y => new CacheProxy(y));
});
}
private static DebuggingState ApplyDebugging(Container content)
{
var debuggingState = new DebuggingState();
content.HandleVisitor(x =>
{
x.CreateProxy(y => new DebuggingProxy(debuggingState, y));
});
return debuggingState;
}
internal static void ApplyDefaultTextStyle(this Element content, TextStyle documentDefaultTextStyle)
{
documentDefaultTextStyle.ApplyGlobalStyle(TextStyle.LibraryDefault);
content.HandleVisitor(element =>
{
var text = element as TextBlock;
if (text == null)
return;
foreach (var child in text.Children)
{
if (child is TextBlockSpan textSpan)
textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle);
if (child is TextBlockElement textElement)
ApplyDefaultTextStyle(textElement.Element, documentDefaultTextStyle);
}
});
}
}
}
+32
View File
@@ -0,0 +1,32 @@
using System;
namespace QuestPDF.Drawing
{
public class DocumentMetadata
{
public int ImageQuality { get; set; } = 101;
public int RasterDpi { get; set; } = 72;
public bool PdfA { get; set; }
public string? Title { get; set; }
public string? Author { get; set; }
public string? Subject { get; set; }
public string? Keywords { get; set; }
public string? Creator { get; set; }
public string? Producer { get; set; }
public DateTime CreationDate { get; set; } = DateTime.Now;
public DateTime ModifiedDate { get; set; } = DateTime.Now;
/// <summary>
/// If the number of generated pages exceeds this threshold
/// (likely due to infinite layout), the exception is thrown.
/// </summary>
public int DocumentLayoutExceptionThreshold { get; set; } = 250;
public bool ApplyCaching { get; set; } = !System.Diagnostics.Debugger.IsAttached;
public bool ApplyDebugging { get; set; } = System.Diagnostics.Debugger.IsAttached;
public static DocumentMetadata Default => new DocumentMetadata();
}
}
@@ -0,0 +1,22 @@
using System;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentComposeException : Exception
{
public DocumentComposeException()
{
}
public DocumentComposeException(string message) : base(message)
{
}
public DocumentComposeException(string message, Exception inner) : base(message, inner)
{
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentDrawingException : Exception
{
public DocumentDrawingException()
{
}
public DocumentDrawingException(string message) : base(message)
{
}
public DocumentDrawingException(string message, Exception inner) : base(message, inner)
{
}
}
}

Some files were not shown because too many files have changed in this diff Show More