Compare commits
382 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06b30f2ad6 | |||
| d39f68a974 | |||
| db9d8b5fcf | |||
| a31a588b24 | |||
| cb2a3c6363 | |||
| e775f62fab | |||
| 056e3f244c | |||
| cd3f7f5a25 | |||
| a5805f6e43 | |||
| abe7b2f14c | |||
| 3e485a572c | |||
| fd0bb5b089 | |||
| cc51b62b73 | |||
| 8e16b5ad4f | |||
| 71e2743409 | |||
| ba9d3aa04b | |||
| 2a0b133185 | |||
| 6058dac524 | |||
| 25b8f62245 | |||
| 2c31f3d5b5 | |||
| f7cd89ccf6 | |||
| 6914a9063a | |||
| b87e8d5d4e | |||
| d740d67a64 | |||
| a14e9ca61f | |||
| 44b3ff8d0d | |||
| df6b88e14a | |||
| d4103797aa | |||
| d894914e7e | |||
| 90d1ce7af7 | |||
| 5fa32a06cc | |||
| acdf1ed1aa | |||
| a0b32e5ecf | |||
| 539dc83303 | |||
| d97fa2cef1 | |||
| 6d122c784d | |||
| 28743a81d1 | |||
| 1047854f77 | |||
| c5fbf7263c | |||
| fae2205ff8 | |||
| 1cbe4b1dc8 | |||
| 32b94cea43 | |||
| 0ca55a91e0 | |||
| 09e6b5253f | |||
| bacb136a3f | |||
| b7bc640e31 | |||
| 6e6f884a5f | |||
| b47a8ac409 | |||
| e51082400c | |||
| 52cfa3ab7e | |||
| cd181b1e2e | |||
| e71601ad0c | |||
| 3041aa53cc | |||
| 0ebf2833af | |||
| 25e6d9fbca | |||
| f80149792d | |||
| 2beee1d22e | |||
| 1af7c0a144 | |||
| eeca67e5bc | |||
| 4da3ef5dfa | |||
| f3d4151273 | |||
| 9a7e397db2 | |||
| d81f21e658 | |||
| 78909c6edf | |||
| a2d81b6adf | |||
| 4a761c023f | |||
| 24bbd06dff | |||
| 44bd646bab | |||
| 5f0291b2c4 | |||
| 1b91015d8f | |||
| 2b6444463d | |||
| a2629575e8 | |||
| c8824021cc | |||
| e1101d870d | |||
| 152304b467 | |||
| 8a1be90c4f | |||
| bc8a9e5dc5 | |||
| e54e09de15 | |||
| c49a424f87 | |||
| c63b0658f3 | |||
| 82cd1d7835 | |||
| 3ffab6e933 | |||
| e4d55e0298 | |||
| a6f4fd7f49 | |||
| 048a4748b2 | |||
| 8cc2fb8696 | |||
| 8e7b528cd9 | |||
| 26193313b8 | |||
| 555825e8be | |||
| ddde8e7517 | |||
| d2c82b5988 | |||
| d82aae95b5 | |||
| 5c11a2ab6a | |||
| 03e3a80fd9 | |||
| 4692c5ce62 | |||
| 919f916219 | |||
| 7a32f774a1 | |||
| fba71e6392 | |||
| e27585a504 | |||
| 9be497ee41 | |||
| 0fc0db55d2 | |||
| 9e7a1ed49d | |||
| c137bcfcde | |||
| b80b3414d8 | |||
| 5f7cee3420 | |||
| 435c42ab9e | |||
| 7b4923b45d | |||
| 8732b7e50b | |||
| 6b31322f92 | |||
| 6155d21207 | |||
| a0909eb057 | |||
| 11ff53946d | |||
| 0711bca1e1 | |||
| 297ca48c70 | |||
| d2601e9e5a | |||
| 421a926780 | |||
| 307759d1b3 | |||
| 00bcb2c25b | |||
| e430484e85 | |||
| d24d887a3a | |||
| 404914ea7e | |||
| 545b76fd40 | |||
| c801894ec4 | |||
| c21744e7de | |||
| 734d116bfe | |||
| 0abb67b748 | |||
| 828bb86737 | |||
| 040c47e017 | |||
| ff95fe287a | |||
| 47e9a49fe5 | |||
| b2826a06b8 | |||
| 321cba32ce | |||
| 26fdbb714d | |||
| f0cec8988a | |||
| ea2102fe4c | |||
| 6cca3ed057 | |||
| 9afe4ec104 | |||
| 846679007f | |||
| 0946607154 | |||
| d5f86e0d70 | |||
| 346513ee85 | |||
| d18ee5f282 | |||
| a85bc0abc1 | |||
| 82e39df572 | |||
| 1311b6db32 | |||
| b5645bfbd5 | |||
| 8217b3b54a | |||
| 726759f47a | |||
| bbd9c3379e | |||
| 697c5e238d | |||
| 21a92be87e | |||
| b0cca1ff48 | |||
| 78c5049eda | |||
| 3d0ca07b43 | |||
| a67fa754af | |||
| 208235ad1e | |||
| f24416474a | |||
| 01c2e8d3f5 | |||
| b3cef238ec | |||
| aede62c135 | |||
| db9db95dcc | |||
| 92263685d7 | |||
| ba4be521aa | |||
| f6967dfe8b | |||
| ff3dfe7831 | |||
| 5a1990d857 | |||
| 1b9b164583 | |||
| 9c64a6bc8d | |||
| 5402e5fedc | |||
| 2c14f91ebe | |||
| b533a32b61 | |||
| 262bd3c182 | |||
| fdf8e3eb1a | |||
| fcff989ab2 | |||
| 054e7a5f20 | |||
| a92cc25fb1 | |||
| 8db283d559 | |||
| 456c7a735b | |||
| 5bf2a9a3d3 | |||
| 8a64abaac2 | |||
| 68df390d0e | |||
| d73c694452 | |||
| 69e268733c | |||
| 657bbe2aac | |||
| 4479a49ad0 | |||
| 63288dfb60 | |||
| fc325d8b76 | |||
| 5ffeaa3075 | |||
| fe431fbc12 | |||
| e0de408821 | |||
| 8ce6afef5a | |||
| 1c70b20028 | |||
| 3aef4ec4c9 | |||
| 3649607bd9 | |||
| 9a6b11ab85 | |||
| ac29ed4794 | |||
| 5f7da8b5b3 | |||
| 78eef45ce2 | |||
| 5424d9f0a0 | |||
| 946fe91a98 | |||
| b5839d3989 | |||
| 2ca6d1cb47 | |||
| 49a3371af7 | |||
| 3f3ada6d8a | |||
| ba409a8712 | |||
| b96c67a8af | |||
| b9fbb9267f | |||
| 272b0fc11a | |||
| b2cc7bbd36 | |||
| e3ce194fd1 | |||
| 9b892c86ed | |||
| c9833d410d | |||
| f8057a840c | |||
| a2ce31022c | |||
| 763fdfac0f | |||
| ba8b35b1c0 | |||
| 648a359d15 | |||
| 630d3389d3 | |||
| a7c3c88e81 | |||
| 9524cc6eb1 | |||
| 4152b67679 | |||
| 8020cb30cb | |||
| 9358fb8937 | |||
| eb297177ea | |||
| 7f651932b9 | |||
| caaae5fa1c | |||
| f76caa28b1 | |||
| ea92655ef5 | |||
| 3f8463e9b7 | |||
| 02e25b193d | |||
| 7cc272ff9e | |||
| b8ea30be23 | |||
| 06418238dc | |||
| ed73c5b82d | |||
| 96732b5856 | |||
| c7008ad940 | |||
| 940616cd3e | |||
| 01a80032b0 | |||
| 3e5e3843d2 | |||
| d3911d5687 | |||
| 82e4dd36f0 | |||
| 561d6a004c | |||
| 59b77e55d4 | |||
| ea398c562f | |||
| cb493562fc | |||
| 5f636beb9d | |||
| 5b85ae2627 | |||
| 10683776bb | |||
| f2c47c4fd3 | |||
| 77b8f04659 | |||
| 5235ada66f | |||
| 4ce66878f2 | |||
| 79cc5f1507 | |||
| 7c7d461c4b | |||
| 63af713935 | |||
| 2419a25cbd | |||
| 014ec15908 | |||
| 82e29d5fdd | |||
| c64754241d | |||
| 9de87061e4 | |||
| 86cfd22316 | |||
| 520bfc840c | |||
| 22cdad69b7 | |||
| d260fa7587 | |||
| 011668fb4c | |||
| 5a886452cf | |||
| b044208195 | |||
| dadb8a5087 | |||
| 11f0809efc | |||
| 0a6673dd4f | |||
| 525bf534e5 | |||
| 68f050a154 | |||
| fd696c5b66 | |||
| 0ccc8cc236 | |||
| 9ef444462a | |||
| 479915b68f | |||
| 5deea91fe4 | |||
| 7174a2afa1 | |||
| 1371fe1df9 | |||
| bb00dfd4d4 | |||
| 70e5783f0e | |||
| e8b7f38187 | |||
| c2ba2addfc | |||
| e379502a64 | |||
| 88e58500a8 | |||
| caa779e1e0 | |||
| 4938e97e6d | |||
| 7980befb77 | |||
| f3b75b43ac | |||
| 17e2727833 | |||
| 1b9ea70f6e | |||
| 87f4c9774a | |||
| 3bdd03031b | |||
| 26335faa97 | |||
| 7b81e61840 | |||
| 391c5a6092 | |||
| d951e0a6b2 | |||
| 188fbc22a7 | |||
| cc6d1c81c8 | |||
| 6d333da84c | |||
| e411554a29 | |||
| 9fddea84ba | |||
| 84e896e13b | |||
| 569864d48a | |||
| 2c11491d4e | |||
| acdd8164be | |||
| 094b25a9fb | |||
| 122f35d0a7 | |||
| f4c9f8b3c2 | |||
| ae7873680d | |||
| 175db288f6 | |||
| 22401be791 | |||
| e2774ef347 | |||
| 99f004dd85 | |||
| 8ada092531 | |||
| c334390af0 | |||
| deed219a0a | |||
| bb8e590fc6 | |||
| a08a7b85c9 | |||
| 755447e1fd | |||
| b66a53a189 | |||
| 6d41ac9b9a | |||
| a124d23862 | |||
| 5f65b2daed | |||
| 07938a1510 | |||
| f17860f519 | |||
| 6023b4de34 | |||
| 748b8f65f5 | |||
| feab280a27 | |||
| ae32511172 | |||
| 6c4da7285a | |||
| 070b6a20bd | |||
| f7cfdb763f | |||
| 5975b19445 | |||
| fb7743e828 | |||
| eca93b7e66 | |||
| 6a3bfd855e | |||
| 5e7f2a3adf | |||
| 2f1dd4b383 | |||
| adec37007b | |||
| 814d325376 | |||
| 4152a0f701 | |||
| 6c80c59996 | |||
| 08a37666fe | |||
| c2fb68562d | |||
| 683ab362d8 | |||
| 3bb46ecc42 | |||
| 3112ee10cf | |||
| 899c138842 | |||
| 5177dcfd2b | |||
| 4e6415aee2 | |||
| d9b3f016e8 | |||
| b9cfaf3846 | |||
| e3e7a22af8 | |||
| c938ea32b0 | |||
| 69419c8440 | |||
| 23e8aa3491 | |||
| fd5d51e764 | |||
| dbc479db07 | |||
| 04af33fc31 | |||
| edc595d199 | |||
| 7f94ae589a | |||
| adfce6204e | |||
| 6d3c8d0708 | |||
| 3b8c300126 | |||
| 239a042615 | |||
| 49fb6dadb3 | |||
| c79a4a0c08 | |||
| 31191efd88 | |||
| 20fe49dd01 | |||
| 7cdc1fcee2 | |||
| 14f11232be | |||
| c05c5e1597 | |||
| 07f1eb99b9 | |||
| 44d7538578 | |||
| b894262f7e | |||
| 4423774648 | |||
| 5d4f1f530a | |||
| 3ba8185871 | |||
| 78e5cbd098 | |||
| f792f6c749 | |||
| 0d86039c0c |
+131
@@ -0,0 +1,131 @@
|
||||
# Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\GithubRepos\QuestPDF codebase based on best match to current usage at 16.03.2022
|
||||
# You can modify the rules from these initially generated values to suit your own policies
|
||||
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
[*.cs]
|
||||
|
||||
|
||||
#Core editorconfig formatting - indentation
|
||||
|
||||
#use soft tabs (spaces) for indentation
|
||||
indent_style = space
|
||||
|
||||
#Formatting - new line options
|
||||
|
||||
#place catch statements on a new line
|
||||
csharp_new_line_before_catch = true
|
||||
#place else statements on a new line
|
||||
csharp_new_line_before_else = true
|
||||
#require members of anonymous types to be on separate lines
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
#require members of object intializers to be on separate lines
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
#require braces to be on a new line for object_collection_array_initializers, methods, anonymous_types, control_blocks, types, and lambdas (also known as "Allman" style)
|
||||
csharp_new_line_before_open_brace =all
|
||||
|
||||
#Formatting - organize using options
|
||||
|
||||
#sort System.* using directives alphabetically, and place them before other usings
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
#Formatting - spacing options
|
||||
|
||||
#require NO space between a cast and the value
|
||||
csharp_space_after_cast = false
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
#require a space after a keyword in a control flow statement such as a for loop
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
#require a space before the colon for bases or interfaces in a type declaration
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
#remove space within empty argument list parentheses
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
#remove space between method call name and opening parenthesis
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
#remove space within empty parameter list parentheses for a method declaration
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
|
||||
#Formatting - wrapping options
|
||||
|
||||
#leave code block on single line
|
||||
csharp_preserve_single_line_blocks = true
|
||||
|
||||
#Style - Code block preferences
|
||||
|
||||
#prefer no curly braces if allowed
|
||||
csharp_prefer_braces = false:suggestion
|
||||
|
||||
#Style - expression bodied member options
|
||||
|
||||
#prefer block bodies for constructors
|
||||
csharp_style_expression_bodied_constructors = false:suggestion
|
||||
#prefer block bodies for methods
|
||||
csharp_style_expression_bodied_methods = false:suggestion
|
||||
#prefer expression-bodied members for properties
|
||||
csharp_style_expression_bodied_properties = true:suggestion
|
||||
|
||||
#Style - expression level options
|
||||
|
||||
#prefer out variables to be declared inline in the argument list of a method call when possible
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
#Style - Expression-level preferences
|
||||
|
||||
#prefer objects to be initialized using object initializers when possible
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
#prefer inferred anonymous type member names
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
|
||||
#prefer inferred tuple element names
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
|
||||
#Style - implicit and explicit types
|
||||
|
||||
#prefer var over explicit type in all cases, unless overridden by another code style rule
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
#prefer var is used to declare variables with built-in system types such as int
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
|
||||
#Style - language keyword and framework type options
|
||||
|
||||
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
|
||||
#Style - Miscellaneous preferences
|
||||
|
||||
#prefer local functions over anonymous functions
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
|
||||
#Style - modifier options
|
||||
|
||||
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
#Style - Modifier preferences
|
||||
|
||||
#when this rule is set to a list of modifiers, prefer the specified ordering.
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
|
||||
#Style - Pattern matching
|
||||
|
||||
#prefer pattern matching instead of is expression with type casts
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
|
||||
#Style - qualification options
|
||||
|
||||
#prefer fields not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
#prefer methods not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
#prefer properties not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
|
||||
[*.{cs,vb}]
|
||||
tab_width=4
|
||||
indent_size=4
|
||||
@@ -0,0 +1,70 @@
|
||||
# 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
|
||||
@@ -0,0 +1 @@
|
||||
github: QuestPDF
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class BarcodeExamples
|
||||
{
|
||||
[Test]
|
||||
public void Example()
|
||||
{
|
||||
FontManager.RegisterFont(File.OpenRead("LibreBarcode39-Regular.ttf"));
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 200)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background(Colors.White)
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
.Text("*QuestPDF*")
|
||||
.FontFamily("Libre Barcode 39")
|
||||
.FontSize(64);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Microcharts;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class CanvasExamples
|
||||
{
|
||||
[Test]
|
||||
public void BorderRadius()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(175, 100)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Padding(25)
|
||||
.MinimalBox()
|
||||
.Layers(layers =>
|
||||
{
|
||||
layers.Layer().Canvas((canvas, size) =>
|
||||
{
|
||||
DrawRoundedRectangle(Colors.White, false);
|
||||
DrawRoundedRectangle(Colors.Blue.Darken2, true);
|
||||
|
||||
void DrawRoundedRectangle(string color, bool isStroke)
|
||||
{
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Color = SKColor.Parse(color),
|
||||
IsStroke = isStroke,
|
||||
StrokeWidth = 2,
|
||||
IsAntialias = true
|
||||
};
|
||||
|
||||
canvas.DrawRoundRect(0, 0, size.Width, size.Height, 20, 20, paint);
|
||||
}
|
||||
});
|
||||
|
||||
layers
|
||||
.PrimaryLayer()
|
||||
.PaddingVertical(10)
|
||||
.PaddingHorizontal(20)
|
||||
.Text("Sample text")
|
||||
.FontSize(16)
|
||||
.FontColor(Colors.Blue.Darken2)
|
||||
.SemiBold();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using Microcharts;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ChartExample
|
||||
{
|
||||
[Test]
|
||||
public void MicrochartChart()
|
||||
{
|
||||
var entries = new[]
|
||||
{
|
||||
new ChartEntry(212)
|
||||
{
|
||||
Label = "UWP",
|
||||
ValueLabel = "112",
|
||||
Color = SKColor.Parse("#2c3e50")
|
||||
},
|
||||
new ChartEntry(248)
|
||||
{
|
||||
Label = "Android",
|
||||
ValueLabel = "648",
|
||||
Color = SKColor.Parse("#77d065")
|
||||
},
|
||||
new ChartEntry(128)
|
||||
{
|
||||
Label = "iOS",
|
||||
ValueLabel = "428",
|
||||
Color = SKColor.Parse("#b455b6")
|
||||
},
|
||||
new ChartEntry(514)
|
||||
{
|
||||
Label = "Forms",
|
||||
ValueLabel = "214",
|
||||
Color = SKColor.Parse("#3498db")
|
||||
}
|
||||
};
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 600)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background(Colors.White)
|
||||
.Padding(25)
|
||||
.Column(column =>
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.PaddingBottom(10)
|
||||
.Text("Chart example")
|
||||
.FontSize(20)
|
||||
.SemiBold()
|
||||
.FontColor(Colors.Blue.Medium);
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Border(1)
|
||||
.ExtendHorizontal()
|
||||
.Height(300)
|
||||
.Canvas((canvas, size) =>
|
||||
{
|
||||
var chart = new BarChart
|
||||
{
|
||||
Entries = entries,
|
||||
|
||||
LabelOrientation = Orientation.Horizontal,
|
||||
ValueLabelOrientation = Orientation.Horizontal,
|
||||
|
||||
IsAnimated = false,
|
||||
};
|
||||
|
||||
chart.DrawContent(canvas, (int)size.Width, (int)size.Height);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ColumnExamples
|
||||
{
|
||||
[Test]
|
||||
public void Column()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ShowResults()
|
||||
.ProducePdf()
|
||||
.Render(container =>
|
||||
{
|
||||
container.Column(column =>
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, 10))
|
||||
column.Item().Element(Block);
|
||||
|
||||
static void Block(IContainer container)
|
||||
{
|
||||
container
|
||||
.Width(72)
|
||||
.Height(3.5f, Unit.Inch)
|
||||
.Height(1.5f, Unit.Inch)
|
||||
.Background(Placeholders.BackgroundColor());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Stability_NoItems()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.MaxPages(100)
|
||||
.PageSize(250, 150)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Column(column => { });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ComplexLayoutBenchmark
|
||||
{
|
||||
[Test]
|
||||
public void ComplexLayout()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(x => GenerateStructure(x, 12));
|
||||
}
|
||||
|
||||
private void GenerateStructure(IContainer container, int level)
|
||||
{
|
||||
if (level <= 0)
|
||||
{
|
||||
container.Background(Placeholders.BackgroundColor()).Height(10);
|
||||
return;
|
||||
}
|
||||
|
||||
level--;
|
||||
|
||||
if (level % 3 == 0)
|
||||
{
|
||||
container
|
||||
.Border(level / 4f)
|
||||
.BorderColor(Colors.Black)
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeItem().Element(x => GenerateStructure(x, level));
|
||||
row.RelativeItem().Element(x => GenerateStructure(x, level));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
container
|
||||
.Border(level / 4f)
|
||||
.BorderColor(Colors.Black)
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Element(x => GenerateStructure(x, level));
|
||||
column.Item().Element(x => GenerateStructure(x, level));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ContinuousPageDocument : IDocument
|
||||
{
|
||||
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(20);
|
||||
page.ContinuousSize(150);
|
||||
|
||||
page.Header().Text("Header");
|
||||
|
||||
page.Content().PaddingVertical(10).Border(1).Padding(10).Column(column =>
|
||||
{
|
||||
foreach (var index in Enumerable.Range(1, 100))
|
||||
column.Item().Text($"Line {index}").FontColor(Placeholders.Color());
|
||||
});
|
||||
|
||||
page.Footer().Text("Footer");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ContinuousPageExamples
|
||||
{
|
||||
[Test]
|
||||
public void ContinuousPage()
|
||||
{
|
||||
var path = "example.pdf";
|
||||
new ContinuousPageDocument().GeneratePdf(path);
|
||||
Process.Start("explorer", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.Exceptions;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class DebuggingTesting
|
||||
{
|
||||
[Test]
|
||||
public void Column()
|
||||
{
|
||||
Assert.Throws<DocumentLayoutException>(() =>
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 360)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Width(100)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.DebugPointer("Example debug pointer")
|
||||
.Column(x =>
|
||||
{
|
||||
x.Item().Text("Test");
|
||||
x.Item().Width(150);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Simple()
|
||||
{
|
||||
Assert.Throws<DocumentLayoutException>(() =>
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 360)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Width(100)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.Width(150)
|
||||
.Text("Test");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DebugPointer()
|
||||
{
|
||||
Assert.Throws<DocumentLayoutException>(() =>
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 360)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.Padding(10)
|
||||
.Width(100)
|
||||
.DebugPointer("Example debug pointer")
|
||||
.Width(150)
|
||||
.Text("Example");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class DefaultTextStyleExample
|
||||
{
|
||||
[Test]
|
||||
public void DefaultTextStyle()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
// all text in this set of pages has size 20
|
||||
page.DefaultTextStyle(TextStyle.Default.Size(20));
|
||||
|
||||
page.Margin(20);
|
||||
page.Size(PageSizes.A4);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Text(Placeholders.Sentence());
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
// text in this block is additionally semibold
|
||||
text.DefaultTextStyle(TextStyle.Default.SemiBold());
|
||||
|
||||
text.Line(Placeholders.Sentence());
|
||||
|
||||
// this text has size 20 but also semibold and red
|
||||
text.Span(Placeholders.Sentence()).FontColor(Colors.Red.Medium);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class DefaultTextStyleExamples
|
||||
{
|
||||
[Test]
|
||||
public void Placeholder()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(220, 270)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.EnableDebugging()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.DefaultTextStyle(TextStyle.Default.Bold().Underline())
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Text("Default style applies to all children");
|
||||
column.Item().Text("You can override certain styles").Underline(false).FontColor(Colors.Green.Darken2);
|
||||
|
||||
column.Item().PaddingTop(10).Border(1).Grid(grid =>
|
||||
{
|
||||
grid.Columns(4);
|
||||
|
||||
foreach (var i in Enumerable.Range(1, 16))
|
||||
{
|
||||
grid.Item()
|
||||
.Border(1)
|
||||
.BorderColor(Colors.Grey.Lighten1)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.Width(50)
|
||||
.Height(50)
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
.Text(i)
|
||||
.FontSize(16 + i / 4);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class DifferentHeaderOnFirstPageExample
|
||||
{
|
||||
[Test]
|
||||
public void Placeholder()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A6)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.EnableDebugging()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A6);
|
||||
page.Margin(5);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Header().Column(column =>
|
||||
{
|
||||
column.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(60);
|
||||
column.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(40);
|
||||
});
|
||||
|
||||
page.Content().PaddingVertical(10).Column(column =>
|
||||
{
|
||||
column.Spacing(10);
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, 13))
|
||||
column.Item().Background(Colors.Grey.Lighten2).Height(40);
|
||||
});
|
||||
|
||||
page.Footer().AlignCenter().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.Size(16));
|
||||
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public struct FibonacciHeaderState
|
||||
{
|
||||
public int Previous { get; set; }
|
||||
public int Current { get; set; }
|
||||
}
|
||||
|
||||
public class FibonacciHeader : IDynamicComponent<FibonacciHeaderState>
|
||||
{
|
||||
public FibonacciHeaderState State { get; set; }
|
||||
|
||||
public static readonly string[] ColorsTable =
|
||||
{
|
||||
Colors.Red.Lighten2,
|
||||
Colors.Orange.Lighten2,
|
||||
Colors.Green.Lighten2,
|
||||
};
|
||||
|
||||
public FibonacciHeader(int previous, int current)
|
||||
{
|
||||
State = new FibonacciHeaderState
|
||||
{
|
||||
Previous = previous,
|
||||
Current = current
|
||||
};
|
||||
}
|
||||
|
||||
public DynamicComponentComposeResult Compose(DynamicContext context)
|
||||
{
|
||||
var content = context.CreateElement(container =>
|
||||
{
|
||||
var colorIndex = State.Current % ColorsTable.Length;
|
||||
var color = ColorsTable[colorIndex];
|
||||
|
||||
var ratio = (float)State.Current / State.Previous;
|
||||
|
||||
container
|
||||
.Background(color)
|
||||
.Height(50)
|
||||
.AlignMiddle()
|
||||
.AlignCenter()
|
||||
.Text($"{State.Current} / {State.Previous} = {ratio:N5}");
|
||||
});
|
||||
|
||||
State = new FibonacciHeaderState
|
||||
{
|
||||
Previous = State.Current,
|
||||
Current = State.Previous + State.Current
|
||||
};
|
||||
|
||||
return new DynamicComponentComposeResult
|
||||
{
|
||||
Content = content,
|
||||
HasMoreContent = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicFibonacci
|
||||
{
|
||||
[Test]
|
||||
public static void Dynamic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ShowResults()
|
||||
.MaxPages(100)
|
||||
.ProduceImages()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A6);
|
||||
page.PageColor(Colors.White);
|
||||
page.Margin(1, Unit.Centimetre);
|
||||
page.DefaultTextStyle(x => x.FontSize(18));
|
||||
|
||||
page.Header().Dynamic(new FibonacciHeader(17, 19));
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, 50))
|
||||
column.Item().PaddingTop(25).Background(Colors.Grey.Lighten2).Height(50);
|
||||
});
|
||||
|
||||
page.Footer().AlignCenter().Text(text =>
|
||||
{
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class OrderItem
|
||||
{
|
||||
public string ItemName { get; set; } = Placeholders.Label();
|
||||
public int Price { get; set; } = Placeholders.Random.Next(1, 11) * 10;
|
||||
public int Count { get; set; } = Placeholders.Random.Next(1, 11);
|
||||
}
|
||||
|
||||
public struct OrdersTableState
|
||||
{
|
||||
public int ShownItemsCount { get; set; }
|
||||
}
|
||||
|
||||
public class OptimizedOrdersTable : IDynamicComponent<OrdersTableState>
|
||||
{
|
||||
private ICollection<OrderItem> Items { get; }
|
||||
public OrdersTableState State { get; set; }
|
||||
|
||||
public OptimizedOrdersTable(ICollection<OrderItem> items)
|
||||
{
|
||||
Items = items;
|
||||
|
||||
State = new OrdersTableState
|
||||
{
|
||||
ShownItemsCount = 0
|
||||
};
|
||||
}
|
||||
|
||||
public DynamicComponentComposeResult Compose(DynamicContext context)
|
||||
{
|
||||
var header = ComposeHeader(context);
|
||||
var sampleFooter = ComposeFooter(context, Enumerable.Empty<OrderItem>());
|
||||
var decorationHeight = header.Size.Height + sampleFooter.Size.Height;
|
||||
|
||||
var rows = GetItemsForPage(context, decorationHeight).ToList();
|
||||
var footer = ComposeFooter(context, rows.Select(x => x.Item));
|
||||
|
||||
var content = context.CreateElement(container =>
|
||||
{
|
||||
container.MinimalBox().Decoration(decoration =>
|
||||
{
|
||||
decoration.Header().Element(header);
|
||||
|
||||
decoration.Content().Box().Stack(stack =>
|
||||
{
|
||||
foreach (var row in rows)
|
||||
stack.Item().Element(row.Element);
|
||||
});
|
||||
|
||||
decoration.Footer().Element(footer);
|
||||
});
|
||||
});
|
||||
|
||||
State = new OrdersTableState
|
||||
{
|
||||
ShownItemsCount = State.ShownItemsCount + rows.Count
|
||||
};
|
||||
|
||||
return new DynamicComponentComposeResult
|
||||
{
|
||||
Content = content,
|
||||
HasMoreContent = State.ShownItemsCount < Items.Count
|
||||
};
|
||||
}
|
||||
|
||||
private IDynamicElement ComposeHeader(DynamicContext context)
|
||||
{
|
||||
return context.CreateElement(element =>
|
||||
{
|
||||
element
|
||||
.Width(context.AvailableSize.Width)
|
||||
.BorderBottom(1)
|
||||
.BorderColor(Colors.Grey.Darken2)
|
||||
.Padding(5)
|
||||
.Row(row =>
|
||||
{
|
||||
var textStyle = TextStyle.Default.SemiBold();
|
||||
|
||||
row.ConstantItem(30).Text("#", textStyle);
|
||||
row.RelativeItem().Text("Item name", textStyle);
|
||||
row.ConstantItem(50).AlignRight().Text("Count", textStyle);
|
||||
row.ConstantItem(50).AlignRight().Text("Price", textStyle);
|
||||
row.ConstantItem(50).AlignRight().Text("Total", textStyle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private IDynamicElement ComposeFooter(DynamicContext context, IEnumerable<OrderItem> items)
|
||||
{
|
||||
var total = items.Sum(x => x.Count * x.Price);
|
||||
|
||||
return context.CreateElement(element =>
|
||||
{
|
||||
element
|
||||
.Width(context.AvailableSize.Width)
|
||||
.Padding(5)
|
||||
.AlignRight()
|
||||
.Text($"Subtotal: {total}$", TextStyle.Default.Size(14).SemiBold());
|
||||
});
|
||||
}
|
||||
|
||||
private IEnumerable<(OrderItem Item, IDynamicElement Element)> GetItemsForPage(DynamicContext context, float decorationHeight)
|
||||
{
|
||||
var totalHeight = decorationHeight;
|
||||
|
||||
foreach (var index in Enumerable.Range(State.ShownItemsCount, Items.Count - State.ShownItemsCount))
|
||||
{
|
||||
var item = Items.ElementAt(index);
|
||||
|
||||
var element = context.CreateElement(content =>
|
||||
{
|
||||
content
|
||||
.Width(context.AvailableSize.Width)
|
||||
.BorderBottom(1)
|
||||
.BorderColor(Colors.Grey.Lighten2)
|
||||
.Padding(5)
|
||||
.Row(row =>
|
||||
{
|
||||
row.ConstantItem(30).Text(index + 1);
|
||||
row.RelativeItem().Text(item.ItemName);
|
||||
row.ConstantItem(50).AlignRight().Text(item.Count);
|
||||
row.ConstantItem(50).AlignRight().Text($"{item.Price}$");
|
||||
row.ConstantItem(50).AlignRight().Text($"{item.Count*item.Price}$");
|
||||
});
|
||||
});
|
||||
|
||||
var elementHeight = element.Size.Height;
|
||||
|
||||
if (totalHeight + elementHeight > context.AvailableSize.Height)
|
||||
break;
|
||||
|
||||
totalHeight += elementHeight;
|
||||
yield return (item, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicOptimizedExamples
|
||||
{
|
||||
[Test]
|
||||
public static void Dynamic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
var items = Enumerable.Range(0, 25).Select(x => new OrderItem()).ToList();
|
||||
|
||||
container
|
||||
.Background(Colors.White)
|
||||
.Padding(25)
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Header()
|
||||
.PaddingBottom(5)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.SemiBold().FontColor(Colors.Blue.Darken2).FontSize(16));
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" of ");
|
||||
text.TotalPages();
|
||||
});
|
||||
|
||||
decoration
|
||||
.Content()
|
||||
.Dynamic(new OptimizedOrdersTable(items));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class FooterWithAlternatingAlignment : IDynamicComponent<int>
|
||||
{
|
||||
public int State { get; set; }
|
||||
|
||||
public DynamicComponentComposeResult Compose(DynamicContext context)
|
||||
{
|
||||
var content = context.CreateElement(element =>
|
||||
{
|
||||
element
|
||||
.Element(x => context.PageNumber % 2 == 0 ? x.AlignLeft() : x.AlignRight())
|
||||
.Text(x =>
|
||||
{
|
||||
x.CurrentPageNumber();
|
||||
x.Span(" / ");
|
||||
x.TotalPages();
|
||||
});
|
||||
});
|
||||
|
||||
return new DynamicComponentComposeResult()
|
||||
{
|
||||
Content = content,
|
||||
HasMoreContent = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicPageNumberLeftRightExamples
|
||||
{
|
||||
[Test]
|
||||
public static void Dynamic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.MaxPages(100)
|
||||
.ShowResults()
|
||||
.ProduceImages()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A6);
|
||||
page.PageColor(Colors.White);
|
||||
page.Margin(1, Unit.Centimetre);
|
||||
page.DefaultTextStyle(x => x.FontSize(18));
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, 50))
|
||||
column.Item().PaddingTop(25).Background(Colors.Grey.Lighten2).Height(50);
|
||||
});
|
||||
|
||||
page.Footer().Dynamic(new FooterWithAlternatingAlignment());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ProgressHeader : IDynamicComponent<int>
|
||||
{
|
||||
public int State { get; set; }
|
||||
|
||||
public DynamicComponentComposeResult Compose(DynamicContext context)
|
||||
{
|
||||
var content = context.CreateElement(container =>
|
||||
{
|
||||
var width = context.AvailableSize.Width * context.PageNumber / context.TotalPages;
|
||||
|
||||
container
|
||||
.Background(Colors.Blue.Lighten2)
|
||||
.Height(25)
|
||||
.Width(width)
|
||||
.Background(Colors.Blue.Darken1);
|
||||
});
|
||||
|
||||
return new DynamicComponentComposeResult
|
||||
{
|
||||
Content = content,
|
||||
HasMoreContent = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicProgressHeader
|
||||
{
|
||||
[Test]
|
||||
public static void Dynamic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ShowResults()
|
||||
.MaxPages(100)
|
||||
.ProduceImages()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A6);
|
||||
page.Margin(1, Unit.Centimetre);
|
||||
page.PageColor(Colors.White);
|
||||
page.DefaultTextStyle(x => x.FontSize(20));
|
||||
|
||||
page.Header().Dynamic(new ProgressHeader());
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, 100))
|
||||
column.Item().PaddingTop(25).Background(Colors.Grey.Lighten2).Height(50);
|
||||
});
|
||||
|
||||
page.Footer().AlignCenter().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.FontSize(20));
|
||||
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class OrdersTable : IDynamicComponent<OrdersTableState>
|
||||
{
|
||||
private IList<OrderItem> Items { get; }
|
||||
public OrdersTableState State { get; set; }
|
||||
|
||||
public OrdersTable(IList<OrderItem> items)
|
||||
{
|
||||
Items = items;
|
||||
|
||||
State = new OrdersTableState
|
||||
{
|
||||
ShownItemsCount = 0
|
||||
};
|
||||
}
|
||||
|
||||
public DynamicComponentComposeResult Compose(DynamicContext context)
|
||||
{
|
||||
var possibleItems = Enumerable
|
||||
.Range(1, Items.Count - State.ShownItemsCount)
|
||||
.Select(itemsToDisplay => ComposeContent(context, itemsToDisplay))
|
||||
.TakeWhile(x => x.Size.Height <= context.AvailableSize.Height)
|
||||
.ToList();
|
||||
|
||||
State = new OrdersTableState
|
||||
{
|
||||
ShownItemsCount = State.ShownItemsCount + possibleItems.Count
|
||||
};
|
||||
|
||||
return new DynamicComponentComposeResult
|
||||
{
|
||||
Content = possibleItems.Last(),
|
||||
HasMoreContent = State.ShownItemsCount < Items.Count
|
||||
};
|
||||
}
|
||||
|
||||
private IDynamicElement ComposeContent(DynamicContext context, int itemsToDisplay)
|
||||
{
|
||||
var total = Items.Skip(State.ShownItemsCount).Take(itemsToDisplay).Sum(x => x.Count * x.Price);
|
||||
|
||||
return context.CreateElement(container =>
|
||||
{
|
||||
container
|
||||
.MinimalBox()
|
||||
.Width(context.AvailableSize.Width)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.ConstantColumn(30);
|
||||
columns.RelativeColumn();
|
||||
columns.ConstantColumn(50);
|
||||
columns.ConstantColumn(50);
|
||||
columns.ConstantColumn(50);
|
||||
});
|
||||
|
||||
table.Header(header =>
|
||||
{
|
||||
header.Cell().Element(Style).Text("#");
|
||||
header.Cell().Element(Style).Text("Item name");
|
||||
header.Cell().Element(Style).AlignRight().Text("Count");
|
||||
header.Cell().Element(Style).AlignRight().Text("Price");
|
||||
header.Cell().Element(Style).AlignRight().Text("Total");
|
||||
|
||||
IContainer Style(IContainer container)
|
||||
{
|
||||
return container
|
||||
.DefaultTextStyle(x => x.SemiBold())
|
||||
.BorderBottom(1)
|
||||
.BorderColor(Colors.Grey.Darken2)
|
||||
.Padding(5);
|
||||
}
|
||||
});
|
||||
|
||||
table.Footer(footer =>
|
||||
{
|
||||
footer
|
||||
.Cell().ColumnSpan(5)
|
||||
.AlignRight()
|
||||
.PaddingTop(10)
|
||||
.Text($"Subtotal: {total}$", TextStyle.Default.Bold());
|
||||
});
|
||||
|
||||
foreach (var index in Enumerable.Range(State.ShownItemsCount, itemsToDisplay))
|
||||
{
|
||||
var item = Items[index];
|
||||
|
||||
table.Cell().Element(Style).Text(index + 1);
|
||||
table.Cell().Element(Style).Text(item.ItemName);
|
||||
table.Cell().Element(Style).AlignRight().Text(item.Count);
|
||||
table.Cell().Element(Style).AlignRight().Text($"{item.Price}$");
|
||||
table.Cell().Element(Style).AlignRight().Text($"{item.Count*item.Price}$");
|
||||
|
||||
IContainer Style(IContainer container)
|
||||
{
|
||||
return container
|
||||
.BorderBottom(1)
|
||||
.BorderColor(Colors.Grey.Lighten2)
|
||||
.Padding(5);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicSimpleTableExample
|
||||
{
|
||||
[Test]
|
||||
public static void Dynamic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ShowResults()
|
||||
.ProduceImages()
|
||||
.Render(container =>
|
||||
{
|
||||
var items = Enumerable.Range(0, 15).Select(x => new OrderItem()).ToList();
|
||||
|
||||
container
|
||||
.Background(Colors.White)
|
||||
.Padding(25)
|
||||
.DefaultTextStyle(x => x.FontSize(16))
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Header()
|
||||
.PaddingBottom(5)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.SemiBold().FontColor(Colors.Blue.Darken2));
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
|
||||
decoration
|
||||
.Content()
|
||||
.Dynamic(new OrdersTable(items));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,95 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExampleTestBase
|
||||
{
|
||||
private readonly Size DefaultImageSize = new Size(400, 300);
|
||||
private const string ResultPath = "Result";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
if (Directory.Exists(ResultPath))
|
||||
Directory.Delete(ResultPath, true);
|
||||
|
||||
Directory.CreateDirectory(ResultPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RunTest()
|
||||
{
|
||||
GetType()
|
||||
.GetMethods()
|
||||
.Where(IsExampleMethod)
|
||||
.ToList()
|
||||
.ForEach(HandleExample);
|
||||
}
|
||||
|
||||
private bool IsExampleMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return parameters.Length == 1 && parameters.First().ParameterType == typeof(IContainer);
|
||||
}
|
||||
|
||||
private T GetAttribute<T>(MethodInfo methodInfo) where T : Attribute
|
||||
{
|
||||
return methodInfo.GetCustomAttributes().FirstOrDefault(y => y is T) as T;
|
||||
}
|
||||
|
||||
private void HandleExample(MethodInfo methodInfo)
|
||||
{
|
||||
var size = GetAttribute<ImageSizeAttribute>(methodInfo)?.Size ?? DefaultImageSize;
|
||||
var fileName = GetAttribute<FileNameAttribute>(methodInfo)?.FileName ?? methodInfo.Name;
|
||||
var showResult = GetAttribute<ShowResultAttribute>(methodInfo) != null;
|
||||
var shouldIgnore = GetAttribute<IgnoreAttribute>(methodInfo) != null;
|
||||
|
||||
if (shouldIgnore)
|
||||
return;
|
||||
|
||||
var container = new Container();
|
||||
methodInfo.Invoke(this, new object[] {container});
|
||||
|
||||
Func<int, string> fileNameSchema = i => $"{fileName.ToLower()}-${i}.png";
|
||||
|
||||
try
|
||||
{
|
||||
var document = new SimpleDocument(container, size);
|
||||
document.GenerateImages(fileNameSchema);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception($"Cannot perform test {fileName}", e);
|
||||
}
|
||||
|
||||
if (showResult)
|
||||
Process.Start("explorer", fileNameSchema(0));
|
||||
}
|
||||
|
||||
private byte[] RenderPage(Element element, Size size)
|
||||
{
|
||||
// scale the result so it is more readable
|
||||
const float scalingFactor = 2;
|
||||
|
||||
var imageInfo = new SKImageInfo((int)(size.Width * scalingFactor), (int)(size.Height * scalingFactor));
|
||||
using var surface = SKSurface.Create(imageInfo);
|
||||
surface.Canvas.Scale(scalingFactor);
|
||||
|
||||
var canvas = new Drawing.Canvas(surface.Canvas);
|
||||
element?.Draw(canvas, size);
|
||||
|
||||
surface.Canvas.Save();
|
||||
return surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class FileNameAttribute : Attribute
|
||||
{
|
||||
public string FileName { get; }
|
||||
|
||||
public FileNameAttribute(string fileName)
|
||||
{
|
||||
FileName = fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class IgnoreAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class ImageSizeAttribute : Attribute
|
||||
{
|
||||
private int Width { get; }
|
||||
private int Height { get; }
|
||||
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
public ImageSizeAttribute(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public enum RenderingTestResult
|
||||
{
|
||||
Pdf,
|
||||
Images
|
||||
}
|
||||
|
||||
public class RenderingTest
|
||||
{
|
||||
private string FileNamePrefix = "test";
|
||||
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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static RenderingTest Create([CallerMemberName] string fileName = "test")
|
||||
{
|
||||
return new RenderingTest().FileName(fileName);
|
||||
}
|
||||
|
||||
public RenderingTest FileName(string fileName)
|
||||
{
|
||||
FileNamePrefix = fileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderingTest PageSize(Size size)
|
||||
{
|
||||
Size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderingTest PageSize(int width, int height)
|
||||
{
|
||||
return PageSize(new Size(width, height));
|
||||
}
|
||||
|
||||
public RenderingTest ProducePdf()
|
||||
{
|
||||
ResultType = RenderingTestResult.Pdf;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderingTest ProduceImages()
|
||||
{
|
||||
ResultType = RenderingTestResult.Images;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderingTest ShowResults()
|
||||
{
|
||||
ShowResult = true;
|
||||
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 =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(new PageSize(Size.Width, Size.Height));
|
||||
page.Content().Container().Background(Colors.White).Element(content);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void RenderDocument(Action<IDocumentContainer> content)
|
||||
{
|
||||
MaxPagesThreshold ??= ResultType == RenderingTestResult.Pdf ? 1000 : 10;
|
||||
var document = new SimpleDocument(content, MaxPagesThreshold.Value, ApplyCaching, ApplyDebugging);
|
||||
|
||||
Render(document);
|
||||
}
|
||||
|
||||
private void Render(IDocument document)
|
||||
{
|
||||
if (ResultType == RenderingTestResult.Images)
|
||||
{
|
||||
Func<int, string> fileNameSchema = i => $"{FileNamePrefix}-${i}.png";
|
||||
document.GenerateImages(fileNameSchema);
|
||||
|
||||
if (ShowResult && ShowingResultsEnabled)
|
||||
Process.Start("explorer", fileNameSchema(0));
|
||||
}
|
||||
|
||||
if (ResultType == RenderingTestResult.Pdf)
|
||||
{
|
||||
var fileName = $"{FileNamePrefix}.pdf";
|
||||
document.GeneratePdf(fileName);
|
||||
|
||||
if (ShowResult && ShowingResultsEnabled)
|
||||
Process.Start("explorer", fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class ShowResultAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using QuestPDF.Drawing;
|
||||
using System;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -7,27 +9,35 @@ namespace QuestPDF.Examples.Engine
|
||||
{
|
||||
public class SimpleDocument : IDocument
|
||||
{
|
||||
private IContainer Container { get; }
|
||||
private Size Size { get; }
|
||||
public const int ImageScalingFactor = 2;
|
||||
|
||||
private Action<IDocumentContainer> Content { get; }
|
||||
private int MaxPages { get; }
|
||||
private bool ApplyCaching { get; }
|
||||
private bool ApplyDebugging { get; }
|
||||
|
||||
public SimpleDocument(IContainer container, Size size)
|
||||
public SimpleDocument(Action<IDocumentContainer> content, int maxPages, bool applyCaching, bool applyDebugging)
|
||||
{
|
||||
Container = container;
|
||||
Size = size;
|
||||
Content = content;
|
||||
MaxPages = maxPages;
|
||||
ApplyCaching = applyCaching;
|
||||
ApplyDebugging = applyDebugging;
|
||||
}
|
||||
|
||||
public DocumentMetadata GetMetadata()
|
||||
{
|
||||
return new DocumentMetadata()
|
||||
{
|
||||
RasterDpi = PageSizes.PointsPerInch * 2,
|
||||
Size = Size
|
||||
RasterDpi = PageSizes.PointsPerInch * ImageScalingFactor,
|
||||
DocumentLayoutExceptionThreshold = MaxPages,
|
||||
ApplyCaching = ApplyCaching,
|
||||
ApplyDebugging = ApplyDebugging
|
||||
};
|
||||
}
|
||||
|
||||
public void Compose(IContainer container)
|
||||
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container.Background("#FFF").Element(Container.Child);
|
||||
Content(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class EnsureSpaceExample
|
||||
{
|
||||
[Test]
|
||||
public void EnsureSpaceWith()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(20);
|
||||
page.Size(PageSizes.A7.Landscape());
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Header().Text("With ensure space").SemiBold();
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.ExtendHorizontal()
|
||||
.Height(75)
|
||||
.Background(Colors.Grey.Lighten2);
|
||||
|
||||
column
|
||||
.Item()
|
||||
.EnsureSpace(100)
|
||||
.Text(Placeholders.LoremIpsum());
|
||||
});
|
||||
|
||||
page.Footer().Text(text =>
|
||||
{
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" out of ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.Exceptions;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ExecutionOrderExamples
|
||||
{
|
||||
[Test]
|
||||
public void Example()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(400, 300)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.DefaultTextStyle(TextStyle.Default.Size(18))
|
||||
.Padding(25)
|
||||
.Row(row =>
|
||||
{
|
||||
row.Spacing(25);
|
||||
|
||||
row.RelativeItem()
|
||||
.Border(1)
|
||||
.Padding(15)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Text("Lorem ipsum");
|
||||
|
||||
row.RelativeItem()
|
||||
.Border(1)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Padding(15)
|
||||
.Text("dolor sit amet");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Example2()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 200)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Border(2)
|
||||
.Width(150)
|
||||
.Height(150)
|
||||
|
||||
.Background(Colors.Blue.Lighten2)
|
||||
.PaddingTop(50)
|
||||
|
||||
.Background(Colors.Green.Lighten2)
|
||||
.PaddingRight(50)
|
||||
|
||||
.Background(Colors.Red.Lighten2)
|
||||
.PaddingBottom(50)
|
||||
|
||||
.Background(Colors.Amber.Lighten2)
|
||||
.PaddingLeft(50)
|
||||
|
||||
.Background(Colors.Grey.Lighten2);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
@@ -11,33 +12,41 @@ namespace QuestPDF.Examples
|
||||
{
|
||||
return container
|
||||
.Border(1)
|
||||
.Background(dark ? "#EEE" : "#FFF")
|
||||
.Padding(10);
|
||||
.BorderColor(Colors.Grey.Medium)
|
||||
.Background(dark ? Colors.Grey.Lighten3 : Colors.White)
|
||||
.Padding(5);
|
||||
}
|
||||
|
||||
public static IContainer LabelCell(this IContainer container) => container.Cell(true);
|
||||
public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text).SemiBold();
|
||||
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: ExampleTestBase
|
||||
public class FrameExample
|
||||
{
|
||||
[ImageSize(550, 400)]
|
||||
[ShowResult]
|
||||
public void Frame(IContainer container)
|
||||
[Test]
|
||||
public void Frame()
|
||||
{
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Stack(stack =>
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(550, 400)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
for(var i=1; i<=4; i++)
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Column(column =>
|
||||
{
|
||||
row.RelativeColumn(2).LabelCell().Text(Placeholders.Label());
|
||||
row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph());
|
||||
for(var i = 1; i <= 4; i++)
|
||||
{
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeItem(2).LabelCell(Placeholders.Label());
|
||||
row.RelativeItem(3).ValueCell().Text(Placeholders.Paragraph());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class GridBenchmark
|
||||
{
|
||||
[Test]
|
||||
public void Benchmark()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ShowResults()
|
||||
.MaxPages(10_000)
|
||||
.EnableCaching(true)
|
||||
.EnableDebugging(false)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Grid(grid =>
|
||||
{
|
||||
const int numberOfRows = 100_000;
|
||||
const int numberOfColumns = 10;
|
||||
|
||||
grid.Columns(numberOfColumns);
|
||||
|
||||
foreach (var row in Enumerable.Range(0, numberOfRows))
|
||||
foreach (var column in Enumerable.Range(0, numberOfColumns))
|
||||
grid.Item().Background(Placeholders.BackgroundColor()).Padding(5).Text($"{row}_{column}");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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).Column(column =>
|
||||
{
|
||||
column.Spacing(25);
|
||||
|
||||
column.Item().Image("logo.png");
|
||||
|
||||
var binaryData = File.ReadAllBytes("logo.png");
|
||||
column.Item().Image(binaryData);
|
||||
|
||||
using var stream = new FileStream("logo.png", FileMode.Open);
|
||||
column.Item().Image(stream);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Exception()
|
||||
{
|
||||
Assert.Throws<DocumentComposeException>(() =>
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A2)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(page => page.Image("non_existent.png"));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class InlinedExamples
|
||||
{
|
||||
[Test]
|
||||
public void Inlined()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(800, 650)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration.Before().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.Size(20));
|
||||
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
|
||||
decoration
|
||||
.Content()
|
||||
.PaddingTop(25)
|
||||
//.MinimalBox()
|
||||
.Border(1)
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Inlined(inlined =>
|
||||
{
|
||||
inlined.Spacing(25);
|
||||
|
||||
inlined.AlignSpaceAround();
|
||||
inlined.BaselineMiddle();
|
||||
|
||||
var random = new Random(123);
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, 50))
|
||||
{
|
||||
var width = random.Next(2, 7);
|
||||
var height = random.Next(2, 7);
|
||||
|
||||
var sizeText = $"{width}×{height}";
|
||||
|
||||
inlined
|
||||
.Item()
|
||||
.Border(1)
|
||||
.Width(width * 25)
|
||||
.Height(height * 25)
|
||||
.Background(Placeholders.BackgroundColor())
|
||||
.Layers(layers =>
|
||||
{
|
||||
layers.Layer().Grid(grid =>
|
||||
{
|
||||
grid.Columns(width);
|
||||
Enumerable.Range(0, width * height).ToList().ForEach(x => grid.Item().Border(1).BorderColor(Colors.White).Width(25).Height(25));
|
||||
});
|
||||
|
||||
layers
|
||||
.PrimaryLayer()
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
.Text(sizeText)
|
||||
.FontSize(15);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Inline_AlignLeft_BaselineBottom()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(800, 600)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(20)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Background(Colors.Grey.Lighten4)
|
||||
.Inlined(inlined =>
|
||||
{
|
||||
inlined.VerticalSpacing(50);
|
||||
inlined.HorizontalSpacing(25);
|
||||
inlined.AlignRight();
|
||||
inlined.BaselineMiddle();
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, 100))
|
||||
inlined.Item().Element(RandomBlock);
|
||||
});
|
||||
});
|
||||
|
||||
void RandomBlock(IContainer container)
|
||||
{
|
||||
container
|
||||
.Width(Placeholders.Random.Next(1, 5) * 20)
|
||||
.Height(Placeholders.Random.Next(1, 5) * 20)
|
||||
.Border(1)
|
||||
.BorderColor(Colors.Grey.Darken2)
|
||||
.Background(Placeholders.BackgroundColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,57 @@
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class LineExamples
|
||||
{
|
||||
[Test]
|
||||
public void LineHorizontal()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(15)
|
||||
.MinimalBox()
|
||||
.DefaultTextStyle(TextStyle.Default.Size(16))
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Text("Above text");
|
||||
column.Item().PaddingVertical(5).LineHorizontal(1).LineColor(Colors.Grey.Medium);
|
||||
column.Item().Text("Below text");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LineVertical()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(15)
|
||||
.DefaultTextStyle(TextStyle.Default.Size(16))
|
||||
.Row(row =>
|
||||
{
|
||||
row.AutoItem().Text("Left text");
|
||||
row.AutoItem().PaddingHorizontal(10).LineVertical(1).LineColor(Colors.Grey.Medium);
|
||||
row.AutoItem().Text("Right text");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Net;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -27,27 +28,34 @@ namespace QuestPDF.Examples
|
||||
}
|
||||
}
|
||||
|
||||
public class LoremPicsumExample : ExampleTestBase
|
||||
public class LoremPicsumExample
|
||||
{
|
||||
[ShowResult]
|
||||
[ImageSize(350, 280)]
|
||||
public void LoremPicsum(IContainer container)
|
||||
[Test]
|
||||
public void LoremPicsum()
|
||||
{
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Stack(column =>
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(350, 280)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
column.Spacing(10);
|
||||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Column(column =>
|
||||
{
|
||||
column.Spacing(10);
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Component(new LoremPicsum(true));
|
||||
column
|
||||
.Item()
|
||||
.Component(new LoremPicsum(true));
|
||||
|
||||
column
|
||||
.Item()
|
||||
.AlignRight()
|
||||
.Text("From Lorem Picsum");
|
||||
column
|
||||
.Item()
|
||||
.AlignRight()
|
||||
.Text("From Lorem Picsum");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Diagnostics;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class MinimalApiExamples
|
||||
{
|
||||
[Test]
|
||||
public void MinimalApi()
|
||||
{
|
||||
Document
|
||||
.Create(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A4);
|
||||
page.Margin(2, Unit.Centimetre);
|
||||
page.PageColor(Colors.White);
|
||||
page.DefaultTextStyle(x => x.FontSize(20));
|
||||
|
||||
page.Header()
|
||||
.Text("Hello PDF!")
|
||||
.SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);
|
||||
|
||||
page.Content()
|
||||
.PaddingVertical(1, Unit.Centimetre)
|
||||
.Column(x =>
|
||||
{
|
||||
x.Spacing(20);
|
||||
|
||||
x.Item().Text(Placeholders.LoremIpsum());
|
||||
x.Item().Image(Placeholders.Image(200, 100));
|
||||
});
|
||||
|
||||
page.Footer()
|
||||
.AlignCenter()
|
||||
.Text(x =>
|
||||
{
|
||||
x.Span("Page ");
|
||||
x.CurrentPageNumber();
|
||||
});
|
||||
});
|
||||
})
|
||||
.GeneratePdf("hello.pdf");
|
||||
|
||||
Process.Start("explorer.exe", "hello.pdf");
|
||||
}
|
||||
}
|
||||
}
|
||||
+138
-106
@@ -1,132 +1,164 @@
|
||||
using QuestPDF.Examples.Engine;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class Examples : ExampleTestBase
|
||||
public class Examples
|
||||
{
|
||||
public void Padding(IContainer container)
|
||||
[Test]
|
||||
public void Padding()
|
||||
{
|
||||
container
|
||||
.Background("#FDD")
|
||||
.Padding(50)
|
||||
|
||||
.Background("#AFA")
|
||||
.PaddingVertical(50)
|
||||
|
||||
.Background("#77F")
|
||||
.PaddingHorizontal(50)
|
||||
|
||||
.Background("#444");
|
||||
}
|
||||
|
||||
public void Border(IContainer container)
|
||||
{
|
||||
container
|
||||
.Background("#EEE")
|
||||
.Padding(25)
|
||||
|
||||
.AlignBottom()
|
||||
.AlignCenter()
|
||||
.BorderBottom(2)
|
||||
.BorderColor("#000")
|
||||
|
||||
.Background("FFF")
|
||||
.Padding(5)
|
||||
.Text("Sample text", TextStyle.Default.FontType("Segoe UI emoji").Alignment(HorizontalAlignment.Center));
|
||||
}
|
||||
|
||||
public void Alignment(IContainer container)
|
||||
{
|
||||
container
|
||||
.Stack(column =>
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 300)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#FFF")
|
||||
|
||||
.AlignLeft()
|
||||
.AlignMiddle()
|
||||
container
|
||||
.Background("#FDD")
|
||||
.Padding(50)
|
||||
|
||||
.Background("#AFA")
|
||||
.PaddingVertical(50)
|
||||
|
||||
.Background("#77F")
|
||||
.PaddingHorizontal(50)
|
||||
|
||||
.Width(50)
|
||||
.Height(50)
|
||||
.Background("#444");
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#DDD")
|
||||
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
|
||||
.Width(50)
|
||||
.Height(50)
|
||||
.Background("#222");
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#BBB")
|
||||
|
||||
.AlignRight()
|
||||
.AlignMiddle()
|
||||
|
||||
.Width(50)
|
||||
.Height(50)
|
||||
.Background("#000");
|
||||
});
|
||||
}
|
||||
|
||||
public void Expand(IContainer container)
|
||||
[Test]
|
||||
public void Border()
|
||||
{
|
||||
container
|
||||
.Stack(column =>
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.Render(container =>
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.Height(150)
|
||||
.Row(row =>
|
||||
container
|
||||
.Background("#EEE")
|
||||
.Padding(25)
|
||||
|
||||
.AlignBottom()
|
||||
.AlignCenter()
|
||||
.BorderBottom(2)
|
||||
.BorderColor("#000")
|
||||
|
||||
.Background("FFF")
|
||||
.Padding(5)
|
||||
.AlignCenter()
|
||||
.Text("Sample text")
|
||||
.FontFamily("Segoe UI emoji");
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Alignment()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Column(column =>
|
||||
{
|
||||
row.RelativeColumn()
|
||||
.Extend()
|
||||
.Background("FFF")
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#FFF")
|
||||
|
||||
.AlignLeft()
|
||||
.AlignMiddle()
|
||||
|
||||
.Height(50)
|
||||
.Width(50)
|
||||
.Background("444");
|
||||
|
||||
row.RelativeColumn()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
|
||||
.Height(50)
|
||||
.ExtendHorizontal()
|
||||
.Background("444");
|
||||
});
|
||||
.Background("#444");
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Height(150)
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeColumn()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#DDD")
|
||||
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
|
||||
.ExtendVertical()
|
||||
.Width(50)
|
||||
.Background("444");
|
||||
|
||||
row.RelativeColumn()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
.Height(50)
|
||||
.Background("#222");
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Height(100)
|
||||
.Background("#BBB")
|
||||
|
||||
.AlignRight()
|
||||
.AlignMiddle()
|
||||
|
||||
.ExtendVertical()
|
||||
.ExtendHorizontal()
|
||||
.Background("444");
|
||||
.Width(50)
|
||||
.Height(50)
|
||||
.Background("#000");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Expand()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(200, 150)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Column(column =>
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.Height(150)
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeItem()
|
||||
.Extend()
|
||||
.Background("FFF")
|
||||
|
||||
.Height(50)
|
||||
.Width(50)
|
||||
.Background("444");
|
||||
|
||||
row.RelativeItem()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
|
||||
.Height(50)
|
||||
.ExtendHorizontal()
|
||||
.Background("444");
|
||||
});
|
||||
|
||||
column
|
||||
.Item()
|
||||
.Height(150)
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeItem()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
|
||||
.ExtendVertical()
|
||||
.Width(50)
|
||||
.Background("444");
|
||||
|
||||
row.RelativeItem()
|
||||
.Extend()
|
||||
.Background("BBB")
|
||||
|
||||
.ExtendVertical()
|
||||
.ExtendHorizontal()
|
||||
.Background("444");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class PageBackgroundForegroundExample
|
||||
{
|
||||
[Test]
|
||||
public void PageBackgroundForeground()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.MaxPages(100)
|
||||
.ShowResults()
|
||||
.RenderDocument(document =>
|
||||
{
|
||||
document.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A4);
|
||||
page.Margin(1, Unit.Inch);
|
||||
page.DefaultTextStyle(TextStyle.Default.FontSize(16));
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
const string transparentBlue = "#662196f3";
|
||||
|
||||
page.Background()
|
||||
.AlignTop()
|
||||
.ExtendHorizontal()
|
||||
.Height(200)
|
||||
.Background(transparentBlue);
|
||||
|
||||
page.Foreground()
|
||||
.AlignBottom()
|
||||
.ExtendHorizontal()
|
||||
.Height(250)
|
||||
.Background(transparentBlue);
|
||||
|
||||
page.Header().Text("Background and foreground").Bold().FontColor(Colors.Blue.Darken2).FontSize(36);
|
||||
|
||||
page.Content().PaddingVertical(25).Column(column =>
|
||||
{
|
||||
column.Spacing(25);
|
||||
|
||||
foreach (var i in Enumerable.Range(0, 100))
|
||||
column.Item().Background(Colors.Grey.Lighten2).Height(75);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,32 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||
<PackageReference Include="microcharts" Version="0.9.5.9" />
|
||||
<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.2" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.4" />
|
||||
<PackageReference Include="Svg.Skia" Version="0.5.10" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="quo-vadis.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="LibreBarcode39-Regular.ttf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="pdf-icon.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class RowExamples
|
||||
{
|
||||
[Test]
|
||||
public void ItemTypes()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.PageSize(650, 300)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().LabelCell("Total width: 600px");
|
||||
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.ConstantItem(150).ValueCell("150px");
|
||||
row.ConstantItem(100).ValueCell("100px");
|
||||
row.RelativeItem(4).ValueCell("200px");
|
||||
row.RelativeItem(3).ValueCell("150px");
|
||||
});
|
||||
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.ConstantItem(100).ValueCell("100px");
|
||||
row.ConstantItem(50).ValueCell("50px");
|
||||
row.RelativeItem(2).ValueCell("100px");
|
||||
row.RelativeItem(1).ValueCell("50px");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Stability()
|
||||
{
|
||||
// up to version 2021.12, this code would always result with the infinite layout exception
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.MaxPages(100)
|
||||
.PageSize(250, 150)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeItem().Column(column =>
|
||||
{
|
||||
column.Item().ShowOnce().Element(CreateBox).Text("X");
|
||||
column.Item().Element(CreateBox).Text("1");
|
||||
column.Item().Element(CreateBox).Text("2");
|
||||
});
|
||||
|
||||
row.RelativeItem().Column(column =>
|
||||
{
|
||||
column.Item().Element(CreateBox).Text("1");
|
||||
column.Item().Element(CreateBox).Text("2");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
static IContainer CreateBox(IContainer container)
|
||||
{
|
||||
return container
|
||||
.ExtendHorizontal()
|
||||
.ExtendVertical()
|
||||
.Background(Colors.Grey.Lighten4)
|
||||
.Border(1)
|
||||
.AlignCenter()
|
||||
.AlignMiddle()
|
||||
.ShowOnce();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Stability_NoItems()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.MaxPages(100)
|
||||
.PageSize(250, 150)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.Row(row => { });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ScaleToFitExamples
|
||||
{
|
||||
[Test]
|
||||
public void ScaleToFit()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container.Padding(25).Column(column =>
|
||||
{
|
||||
var text = Placeholders.Paragraph();
|
||||
|
||||
foreach (var i in Enumerable.Range(2, 5))
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.Width(i * 40)
|
||||
.Height(i * 20)
|
||||
.ScaleToFit()
|
||||
.Text(text);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ShowOnceExample
|
||||
{
|
||||
[Test]
|
||||
public void ShowOnce()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(20);
|
||||
page.Size(PageSizes.A7.Landscape());
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Header().Text("With show once").SemiBold();
|
||||
|
||||
page.Content().PaddingVertical(5).Row(row =>
|
||||
{
|
||||
row.RelativeItem()
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.ShowOnce()
|
||||
.Text(Placeholders.Label());
|
||||
|
||||
row.RelativeItem(2)
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.Text(Placeholders.Paragraph());
|
||||
});
|
||||
|
||||
page.Footer().Text(text =>
|
||||
{
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" out of ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class SkipOnceExample
|
||||
{
|
||||
[Test]
|
||||
public void SkipOnce()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(20);
|
||||
page.Size(PageSizes.A7.Landscape());
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Header().Column(column =>
|
||||
{
|
||||
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.");
|
||||
});
|
||||
|
||||
page.Content()
|
||||
.PaddingVertical(10)
|
||||
.Text(Placeholders.Paragraphs())
|
||||
.FontColor(Colors.Grey.Medium);
|
||||
|
||||
page.Footer().Text(text =>
|
||||
{
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" out of ");
|
||||
text.TotalPages();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class StopPaging
|
||||
{
|
||||
[Test]
|
||||
public void Example()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(300, 250)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.DefaultTextStyle(TextStyle.Default.Size(14))
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Before()
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.SemiBold().Color(Colors.Blue.Medium));
|
||||
|
||||
text.Span("Page ");
|
||||
text.CurrentPageNumber();
|
||||
});
|
||||
|
||||
decoration
|
||||
.Content()
|
||||
.Column(column =>
|
||||
{
|
||||
column.Spacing(25);
|
||||
column.Item().StopPaging().Text(Placeholders.LoremIpsum());
|
||||
column.Item().ExtendHorizontal().Height(75).Background(Colors.Grey.Lighten2);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
using Svg.Skia;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class SvgImageExample
|
||||
{
|
||||
[Test]
|
||||
public void BorderRadius()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(175, 100)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Padding(25)
|
||||
.Canvas((canvas, space) =>
|
||||
{
|
||||
using var svg = new SKSvg();
|
||||
svg.Load("pdf-icon.svg");
|
||||
|
||||
canvas.DrawPicture(svg.Picture);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class TableBenchmark
|
||||
{
|
||||
[Test]
|
||||
public void Benchmark()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ShowResults()
|
||||
.MaxPages(10_000)
|
||||
.EnableCaching(true)
|
||||
.EnableDebugging(false)
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
const int numberOfRows = 100_000;
|
||||
const int numberOfColumns = 10;
|
||||
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
foreach (var _ in Enumerable.Range(0, numberOfColumns))
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
foreach (var row in Enumerable.Range(0, numberOfRows))
|
||||
foreach (var column in Enumerable.Range(0, numberOfColumns))
|
||||
table.Cell().Background(Placeholders.BackgroundColor()).Padding(5).Text($"{row}_{column}");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using IContainer = QuestPDF.Infrastructure.IContainer;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class TableExamples
|
||||
{
|
||||
[Test]
|
||||
public void BasicPlacement()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(220, 220)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
// by using custom 'Element' method, we can reuse visual configuration
|
||||
table.Cell().Row(1).Column(4).Element(Block).Text("A");
|
||||
table.Cell().Row(2).Column(2).Element(Block).Text("B");
|
||||
table.Cell().Row(3).Column(3).Element(Block).Text("C");
|
||||
table.Cell().Row(4).Column(1).Element(Block).Text("D");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PagingSupport()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.PageSize(420, 220)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
// by using custom 'Element' method, we can reuse visual configuration
|
||||
table.Cell().Element(Block).Text(Placeholders.Label());
|
||||
table.Cell().Element(Block).Text(Placeholders.Label());
|
||||
table.Cell().Element(Block).Text(Placeholders.Paragraph());
|
||||
table.Cell().Element(Block).Text(Placeholders.Label());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultCellStyle()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(220, 120)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.DefaultTextStyle(TextStyle.Default.Size(16))
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.Cell().Row(1).Column(1).Element(Block).Text("A");
|
||||
table.Cell().Row(2).Column(2).Element(Block).Text("B");
|
||||
table.Cell().Row(1).Column(3).Element(Block).Text("C");
|
||||
table.Cell().Row(2).Column(4).Element(Block).Text("D");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ColumnsDefinition()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(320, 80)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.ConstantColumn(50);
|
||||
columns.ConstantColumn(100);
|
||||
columns.RelativeColumn(2);
|
||||
columns.RelativeColumn(3);
|
||||
});
|
||||
|
||||
table.Cell().ColumnSpan(4).LabelCell("Total width: 300px");
|
||||
table.Cell().ValueCell("50px");
|
||||
table.Cell().ValueCell("100px");
|
||||
table.Cell().ValueCell("100px");
|
||||
table.Cell().ValueCell("150px");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PartialAutoPlacement()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(220, 220)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.Cell().Element(Block).Text("A");
|
||||
table.Cell().Row(2).Column(2).Element(Block).Text("B");
|
||||
table.Cell().Element(Block).Text("C");
|
||||
table.Cell().Row(3).Column(3).Element(Block).Text("D");
|
||||
table.Cell().ColumnSpan(2).Element(Block).Text("E");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtendLastCellsToTableBottom()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(220, 170)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.ExtendLastCellsToTableBottom();
|
||||
|
||||
table.Cell().Row(1).Column(1).Element(Block).Text("A");
|
||||
table.Cell().Row(3).Column(1).Element(Block).Text("B");
|
||||
table.Cell().Row(2).Column(2).Element(Block).Text("C");
|
||||
table.Cell().Row(3).Column(3).Element(Block).Text("D");
|
||||
table.Cell().Row(2).RowSpan(2).Column(4).Element(Block).Text("E");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Overlapping()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(170, 170)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.Cell().Row(1).RowSpan(3).Column(1).ColumnSpan(3).Background(Colors.Grey.Lighten3).MinHeight(150);
|
||||
table.Cell().Row(1).RowSpan(2).Column(1).ColumnSpan(2).Background(Colors.Grey.Lighten1).MinHeight(100);
|
||||
table.Cell().Row(3).Column(3).Background(Colors.Grey.Darken1).MinHeight(50);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Spans()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(220, 170)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.Cell().RowSpan(2).ColumnSpan(2).Element(Block).Text("1");
|
||||
table.Cell().ColumnSpan(2).Element(Block).Text("2");
|
||||
table.Cell().Element(Block).Text("3");
|
||||
table.Cell().Element(Block).Text("4");
|
||||
table.Cell().RowSpan(2).Element(Block).Text("5");
|
||||
table.Cell().ColumnSpan(2).Element(Block).Text("6");
|
||||
table.Cell().RowSpan(2).Element(Block).Text("7");
|
||||
table.Cell().Element(Block).Text("8");
|
||||
table.Cell().Element(Block).Text("9");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Stability()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(300, 300)
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(10)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.Cell().RowSpan(4).Element(Block).Text("1");
|
||||
|
||||
table.Cell().RowSpan(2).Element(Block).Text("2");
|
||||
table.Cell().RowSpan(1).Element(Block).Text("3");
|
||||
table.Cell().RowSpan(1).Element(Block).Text("4");
|
||||
|
||||
table.Cell().RowSpan(2).Element(Block).Text("5");
|
||||
table.Cell().RowSpan(1).Element(Block).Text("6");
|
||||
table.Cell().RowSpan(1).Element(Block).Text("7");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TableHeader()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.PageSize(500, 200)
|
||||
.ShowResults()
|
||||
.EnableDebugging()
|
||||
.Render(container =>
|
||||
{
|
||||
var pageSizes = new List<(string name, double width, double height)>()
|
||||
{
|
||||
("Letter (ANSI A)", 8.5f, 11),
|
||||
("Legal", 8.5f, 14),
|
||||
("Ledger (ANSI B)", 11, 17),
|
||||
("Tabloid (ANSI B)", 17, 11),
|
||||
("ANSI C", 22, 17),
|
||||
("ANSI D", 34, 22),
|
||||
("ANSI E", 44, 34)
|
||||
};
|
||||
|
||||
const int inchesToPoints = 72;
|
||||
|
||||
container
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Table(table =>
|
||||
{
|
||||
IContainer DefaultCellStyle(IContainer container, string backgroundColor)
|
||||
{
|
||||
return container
|
||||
.Border(1)
|
||||
.BorderColor(Colors.Grey.Lighten1)
|
||||
.Background(backgroundColor)
|
||||
.PaddingVertical(5)
|
||||
.PaddingHorizontal(10)
|
||||
.AlignCenter()
|
||||
.AlignMiddle();
|
||||
}
|
||||
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.RelativeColumn();
|
||||
|
||||
columns.ConstantColumn(75);
|
||||
columns.ConstantColumn(75);
|
||||
|
||||
columns.ConstantColumn(75);
|
||||
columns.ConstantColumn(75);
|
||||
});
|
||||
|
||||
table.Header(header =>
|
||||
{
|
||||
header.Cell().RowSpan(2).Element(CellStyle).ExtendHorizontal().AlignLeft().Text("Document type");
|
||||
|
||||
header.Cell().ColumnSpan(2).Element(CellStyle).Text("Inches");
|
||||
header.Cell().ColumnSpan(2).Element(CellStyle).Text("Points");
|
||||
|
||||
header.Cell().Element(CellStyle).Text("Width");
|
||||
header.Cell().Element(CellStyle).Text("Height");
|
||||
|
||||
header.Cell().Element(CellStyle).Text("Width");
|
||||
header.Cell().Element(CellStyle).Text("Height");
|
||||
|
||||
// you can extend already existing styles by creating additional methods
|
||||
IContainer CellStyle(IContainer container) => DefaultCellStyle(container, Colors.Grey.Lighten3);
|
||||
});
|
||||
|
||||
foreach (var page in pageSizes)
|
||||
{
|
||||
table.Cell().Element(CellStyle).ExtendHorizontal().AlignLeft().Text(page.name);
|
||||
|
||||
// inches
|
||||
table.Cell().Element(CellStyle).Text(page.width);
|
||||
table.Cell().Element(CellStyle).Text(page.height);
|
||||
|
||||
// points
|
||||
table.Cell().Element(CellStyle).Text(page.width * inchesToPoints);
|
||||
table.Cell().Element(CellStyle).Text(page.height * inchesToPoints);
|
||||
|
||||
IContainer CellStyle(IContainer container) => DefaultCellStyle(container, Colors.White);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PerformanceText_TemperatureReport()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProducePdf()
|
||||
.PageSize(PageSizes.A4)
|
||||
.MaxPages(10_000)
|
||||
.EnableCaching()
|
||||
.EnableDebugging(false)
|
||||
.ShowResults()
|
||||
.Render(container => GeneratePerformanceStructure(container, 250));
|
||||
}
|
||||
|
||||
public static void GeneratePerformanceStructure(IContainer container, int repeats)
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
//.Background(Colors.Blue.Lighten2)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
//.Background(Colors.Red.Lighten2)
|
||||
.Table(table =>
|
||||
{
|
||||
table.ColumnsDefinition(columns =>
|
||||
{
|
||||
columns.ConstantColumn(100);
|
||||
columns.RelativeColumn();
|
||||
columns.ConstantColumn(100);
|
||||
columns.RelativeColumn();
|
||||
});
|
||||
|
||||
table.ExtendLastCellsToTableBottom();
|
||||
|
||||
foreach (var i in Enumerable.Range(0, repeats))
|
||||
{
|
||||
table.Cell().RowSpan(3).LabelCell("Project");
|
||||
table.Cell().RowSpan(3).ShowEntire().ValueCell(Placeholders.Sentence());
|
||||
|
||||
table.Cell().LabelCell("Report number");
|
||||
table.Cell().ValueCell(i.ToString());
|
||||
|
||||
table.Cell().LabelCell("Date");
|
||||
table.Cell().ValueCell(Placeholders.ShortDate());
|
||||
|
||||
table.Cell().LabelCell("Inspector");
|
||||
table.Cell().ValueCell("Marcin Ziąbek");
|
||||
|
||||
table.Cell().ColumnSpan(2).LabelCell("Morning weather");
|
||||
table.Cell().ColumnSpan(2).LabelCell("Evening weather");
|
||||
|
||||
table.Cell().ValueCell("Time");
|
||||
table.Cell().ValueCell("7:13");
|
||||
|
||||
table.Cell().ValueCell("Time");
|
||||
table.Cell().ValueCell("18:25");
|
||||
|
||||
table.Cell().ValueCell("Description");
|
||||
table.Cell().ValueCell("Sunny");
|
||||
|
||||
table.Cell().ValueCell("Description");
|
||||
table.Cell().ValueCell("Windy");
|
||||
|
||||
table.Cell().ValueCell("Wind");
|
||||
table.Cell().ValueCell("Mild");
|
||||
|
||||
table.Cell().ValueCell("Wind");
|
||||
table.Cell().ValueCell("Strong");
|
||||
|
||||
table.Cell().ValueCell("Temperature");
|
||||
table.Cell().ValueCell("17°C");
|
||||
|
||||
table.Cell().ValueCell("Temperature");
|
||||
table.Cell().ValueCell("32°C");
|
||||
|
||||
table.Cell().LabelCell("Remarks");
|
||||
table.Cell().ColumnSpan(3).ValueCell(Placeholders.Paragraph());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// this method uses a higher order function to define a custom and dynamic style
|
||||
static IContainer Block(IContainer container)
|
||||
{
|
||||
return container
|
||||
.Border(1)
|
||||
.Background(Colors.Grey.Lighten3)
|
||||
.ShowOnce()
|
||||
.MinWidth(50)
|
||||
.MinHeight(50)
|
||||
.Padding(10)
|
||||
.AlignCenter()
|
||||
.AlignMiddle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class TextBenchmark
|
||||
{
|
||||
[Test]
|
||||
public void Generate()
|
||||
{
|
||||
var chapters = GetBookChapters().ToList();
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.RenderDocument(x => ComposeBook(x, chapters));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Benchmark()
|
||||
{
|
||||
var chapters = GetBookChapters().ToList();
|
||||
|
||||
var results = PerformTest(128).ToList();
|
||||
|
||||
Console.WriteLine($"Min: {results.Min():F}");
|
||||
Console.WriteLine($"Max: {results.Max():F}");
|
||||
Console.WriteLine($"Avg: {results.Average():F}");
|
||||
|
||||
void GenerateDocument()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.RenderDocument(x => ComposeBook(x, chapters));
|
||||
}
|
||||
|
||||
IEnumerable<float> PerformTest(int attempts)
|
||||
{
|
||||
foreach (var i in Enumerable.Range(0, attempts))
|
||||
{
|
||||
var timer = new Stopwatch();
|
||||
|
||||
timer.Start();
|
||||
GenerateDocument();
|
||||
timer.Stop();
|
||||
|
||||
Console.WriteLine($"Attempt {i}: {timer.ElapsedMilliseconds:F}");
|
||||
yield return timer.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BookChapter
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
}
|
||||
|
||||
private static IEnumerable<BookChapter> GetBookChapters()
|
||||
{
|
||||
var book = File.ReadAllLines("quo-vadis.txt");
|
||||
|
||||
var chapterPointers = book
|
||||
.Select((line, index) => new
|
||||
{
|
||||
LineNumber = index,
|
||||
Text = line
|
||||
})
|
||||
.Where(x => x.Text.Length < 50 && x.Text.Contains("Rozdział") || x.Text.Contains("-----"))
|
||||
.Select(x => x.LineNumber)
|
||||
.ToList();
|
||||
|
||||
foreach (var index in Enumerable.Range(0, chapterPointers.Count - 1))
|
||||
{
|
||||
var chapter = chapterPointers[index];
|
||||
|
||||
var title = book[chapter];
|
||||
|
||||
var lineFrom = chapterPointers[index];
|
||||
var lineTo = chapterPointers[index + 1] - 1;
|
||||
|
||||
var lines = book.Skip(lineFrom + 1).Take(lineTo - lineFrom).Where(x => !string.IsNullOrWhiteSpace(x));
|
||||
var content = string.Join(Environment.NewLine, lines);
|
||||
|
||||
yield return new BookChapter
|
||||
{
|
||||
Title = title,
|
||||
Content = content
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ComposeBook(IDocumentContainer container, ICollection<BookChapter> chapters)
|
||||
{
|
||||
var subtitleStyle = TextStyle.Default.Size(24).SemiBold().Color(Colors.Blue.Medium);
|
||||
var normalStyle = TextStyle.Default.Size(14);
|
||||
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Element(Title);
|
||||
column.Item().PageBreak();
|
||||
column.Item().Element(TableOfContents);
|
||||
column.Item().PageBreak();
|
||||
|
||||
Chapters(column);
|
||||
|
||||
column.Item().Element(Acknowledgements);
|
||||
});
|
||||
|
||||
page.Footer().Element(Footer);
|
||||
});
|
||||
|
||||
void Title(IContainer container)
|
||||
{
|
||||
container
|
||||
.Extend()
|
||||
.PaddingBottom(200)
|
||||
.AlignBottom()
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Text("Quo Vadis").FontSize(72).Bold().FontColor(Colors.Blue.Darken2);
|
||||
column.Item().Text("Henryk Sienkiewicz").FontSize(24).FontColor(Colors.Grey.Darken2);
|
||||
});
|
||||
}
|
||||
|
||||
void TableOfContents(IContainer container)
|
||||
{
|
||||
container.Column(column =>
|
||||
{
|
||||
SectionTitle(column, "Spis treści");
|
||||
|
||||
foreach (var chapter in chapters)
|
||||
{
|
||||
column.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));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Chapters(ColumnDescriptor column)
|
||||
{
|
||||
foreach (var chapter in chapters)
|
||||
{
|
||||
column.Item().Element(container => Chapter(container, chapter.Title, chapter.Content));
|
||||
}
|
||||
}
|
||||
|
||||
void Chapter(IContainer container, string title, string content)
|
||||
{
|
||||
container.Column(column =>
|
||||
{
|
||||
SectionTitle(column, title);
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.ParagraphSpacing(5);
|
||||
text.Span(content).Style(normalStyle);
|
||||
});
|
||||
|
||||
column.Item().PageBreak();
|
||||
});
|
||||
}
|
||||
|
||||
void Acknowledgements(IContainer container)
|
||||
{
|
||||
container.Column(column =>
|
||||
{
|
||||
SectionTitle(column, "Podziękowania");
|
||||
|
||||
column.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.Span(". Dziękuję za wspieranie polskiego czytelnictwa!");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void SectionTitle(ColumnDescriptor column, string text)
|
||||
{
|
||||
column.Item().Location(text).Text(text).Style(subtitleStyle);
|
||||
column.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
|
||||
}
|
||||
|
||||
void Footer(IContainer container)
|
||||
{
|
||||
container
|
||||
.AlignCenter()
|
||||
.Text(text =>
|
||||
{
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" / ");
|
||||
text.TotalPages();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
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 SimpleText()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 100)
|
||||
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(5)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(10)
|
||||
.Text(Placeholders.Paragraph());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SimpleTextBlock()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(600, 300)
|
||||
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(5)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.MaxWidth(300)
|
||||
.Padding(10)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.FontSize(20));
|
||||
text.Span("This is a normal text, followed by an ");
|
||||
text.Span("underlined red text").FontColor(Colors.Red.Medium).Underline();
|
||||
text.Span(".");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextWeight()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 500)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(20)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(20)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.FontFamily(Fonts.Calibri).FontSize(20));
|
||||
|
||||
text.Line("Thin").Thin();
|
||||
text.Line("ExtraLight").ExtraLight();
|
||||
text.Line("Light").Light();
|
||||
text.Line("NormalWeight").NormalWeight();
|
||||
text.Line("Medium").Medium();
|
||||
text.Line("SemiBold").SemiBold();
|
||||
text.Line("Bold").Bold();
|
||||
text.Line("ExtraBold").ExtraBold();
|
||||
text.Line("Black").Black();
|
||||
text.Line("ExtraBlack").ExtraBlack();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LineHeight()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 700)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(20)
|
||||
.Column(column =>
|
||||
{
|
||||
var lineHeights = new[] { 0.8f, 1f, 1.5f };
|
||||
var paragraph = Placeholders.Paragraph();
|
||||
|
||||
foreach (var lineHeight in lineHeights)
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.Border(1)
|
||||
.Padding(10)
|
||||
.Text(paragraph)
|
||||
.FontSize(16)
|
||||
.LineHeight(lineHeight);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SuperscriptSubscript_Simple()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 500)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(20)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(20)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.FontSize(20));
|
||||
text.ParagraphSpacing(10);
|
||||
|
||||
var highlight = TextStyle.Default.BackgroundColor(Colors.Green.Lighten3);
|
||||
|
||||
text.Span("E=mc").Style(highlight);
|
||||
text.Span("2").Superscript().Style(highlight);
|
||||
text.Span(" is the equation of mass–energy equivalence.");
|
||||
|
||||
text.EmptyLine();
|
||||
|
||||
text.Span("H").Style(highlight);
|
||||
text.Span("2").Subscript().Style(highlight);
|
||||
text.Span("O").Style(highlight);
|
||||
text.Span(" is the chemical formula for water.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SuperscriptSubscript_Effects()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(800, 400)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.DefaultTextStyle(x => x.FontSize(30))
|
||||
.Column(column =>
|
||||
{
|
||||
column.Spacing(25);
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.Underline());
|
||||
|
||||
text.Span("Underline of the superscript (E = mc");
|
||||
text.Span("2").Superscript();
|
||||
text.Span(") should be at the same height as for normal text.");
|
||||
});
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.Underline());
|
||||
|
||||
text.Span("Underline of the subscript(H");
|
||||
text.Span("2").Subscript();
|
||||
text.Span("O) should be slightly lower than a normal text.");
|
||||
});
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.Strikethrough());
|
||||
|
||||
text.Span("Strikethrough of both superscript (E=mc");
|
||||
text.Span("2").Superscript();
|
||||
text.Span(") and subscript(H");
|
||||
text.Span("2").Subscript();
|
||||
text.Span("O) should be visible in the middle of the text.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParagraphSpacing()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 500)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(5)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(10)
|
||||
.Text(text =>
|
||||
{
|
||||
text.Line(Placeholders.Paragraph());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CustomElement()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 200)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(5)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(10)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.FontSize(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)
|
||||
.MinimalBox()
|
||||
.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? <").Underline();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Textcolumn()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(20)
|
||||
.Padding(10)
|
||||
.MinimalBox()
|
||||
.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)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.Padding(10)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.Bold());
|
||||
|
||||
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, ").Bold();
|
||||
text.Span("this is a red and underlined text, ").FontColor(Colors.Red.Medium).Underline();
|
||||
text.Span("and this is slightly bigger text.").FontSize(16);
|
||||
|
||||
text.EmptyLine();
|
||||
|
||||
text.Span("The new text element also supports injecting custom content between words: ");
|
||||
text.Element().PaddingBottom(-4).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.Hyperlink("Please visit QuestPDF website", "https://www.questpdf.com");
|
||||
|
||||
text.EmptyLine();
|
||||
|
||||
text.Span(Placeholders.Paragraphs());
|
||||
|
||||
|
||||
text.EmptyLine();
|
||||
|
||||
text.Span(Placeholders.Paragraphs()).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)
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.Padding(10)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.FontSize(20).BackgroundColor(Colors.Red.Lighten4));
|
||||
text.AlignLeft();
|
||||
text.ParagraphSpacing(10);
|
||||
|
||||
text.Span("This text is a normal text, ");
|
||||
text.Span("this is a bold text, ").Bold();
|
||||
text.Span("this is a red and underlined text, ").FontColor(Colors.Red.Medium).Underline();
|
||||
text.Span("and this is slightly bigger text.").FontSize(16);
|
||||
|
||||
text.Span("The new text element also supports injecting custom content between words: ");
|
||||
text.Element().PaddingBottom(-4).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.Hyperlink("Please visit QuestPDF website. ", "https://www.questpdf.com");
|
||||
|
||||
text.Span("This is page number ");
|
||||
text.CurrentPageNumber();
|
||||
text.Span(" out of ");
|
||||
text.TotalPages();
|
||||
|
||||
text.EmptyLine();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MeasureIssueWhenSpaceAtLineEnd()
|
||||
{
|
||||
// issue 135
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Text("This is a specially crafted sentence with a specially chosen length for demonstration of the bug that occurs ;;;;;. ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyText()
|
||||
{
|
||||
// issue 135
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Text(" ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Whitespaces()
|
||||
{
|
||||
// issue 135
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Text(" x ").FontSize(11).BackgroundColor(Colors.Red.Lighten3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DrawingNullTextShouldNotThrowException()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Text(null);
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.Span(null);
|
||||
text.Line(null);
|
||||
text.Hyperlink(null, "http://www.questpdf.com");
|
||||
text.TotalPages().Format(x => null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BreakingLongWord()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.PageColor(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Text(null);
|
||||
|
||||
column.Item().Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(x => x.BackgroundColor(Colors.Red.Lighten3).FontSize(24));
|
||||
|
||||
text.Span(" " + Placeholders.LoremIpsum());
|
||||
text.Span(" 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 ").WrapAnywhere();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextShaping_Unicode()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(600, 100)
|
||||
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(35)
|
||||
.MinimalBox()
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Text(text =>
|
||||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.FontSize(20));
|
||||
|
||||
text.Span("Complex Unicode structure: ");
|
||||
|
||||
|
||||
text.Span("T̶̖̔͆͆̽̔ḩ̷̼̫̐̈́̀͜͝͝ì̶͇̤͓̱̣͇͓͉̎s̵̡̟̹͍̜͉̗̾͛̈̐́͋͂͝͠ͅ ̴̨͙͍͇̭̒͗̀́͝ì̷̡̺͉̼̏̏̉̌͝s̷͍͙̗̰̖͙̈̑̂̔͑͊̌̓̊̇͜ ̶̛̼͚͊̅͘ṭ̷̨̘̣̙̖͉͌̏̂̅͑̄̽̕͝ȅ̶̲̲̙̭͈̬̣͔̝͔̈́͝s̸̢̯̪̫͓̭̮̓̀͆͜ț̸̢͉̞̥̤̏̌̓͝").FontFamily(Fonts.Calibri).FontColor(Colors.Red.Medium);
|
||||
|
||||
|
||||
text.Span(".");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextShaping_Arabic()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(500, 100)
|
||||
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container
|
||||
.Padding(25)
|
||||
.MinimalBox()
|
||||
.Background(Colors.Grey.Lighten2)
|
||||
.Text("ينا الألم. في بعض الأحيان ونظراً للالتزامات التي يفرضها علينا")
|
||||
.FontFamily(Fonts.Calibri)
|
||||
.FontSize(20);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="75.320129mm"
|
||||
height="92.604164mm"
|
||||
viewBox="0 0 75.320129 92.604164"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="PDF file icon.svg">
|
||||
<title
|
||||
id="title2682">PDF file icon</title>
|
||||
<defs
|
||||
id="defs2">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath839">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
id="rect841"
|
||||
width="68.688263"
|
||||
height="67.886459"
|
||||
x="-74.033661"
|
||||
y="141.44913" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="122.12727"
|
||||
inkscape:cy="167.02823"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="g899"
|
||||
showgrid="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-page="false"
|
||||
inkscape:snap-others="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>PDF file icon</dc:title>
|
||||
<dc:date>08/10/2018</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Adobe Systems</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>CMetalCore</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:description>Fuente del texto "PDF":
|
||||
Franklin Gothic Medium Cond</dc:description>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Capa 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(36.076172,-93.731774)">
|
||||
<g
|
||||
id="g899"
|
||||
transform="matrix(1.4843054,0,0,1.4843054,17.471885,-90.243502)">
|
||||
<g
|
||||
id="g876">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ff2116;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.11666656;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m -29.632812,123.94727 c -3.551967,0 -6.44336,2.89347 -6.44336,6.44531 v 49.49804 c 0,3.55185 2.891393,6.44532 6.44336,6.44532 H 8.2167969 c 3.5519661,0 6.4433591,-2.89335 6.4433591,-6.44532 v -40.70117 c 0,0 0.101353,-1.19181 -0.416015,-2.35156 -0.484969,-1.08711 -1.275391,-1.84375 -1.275391,-1.84375 a 1.0584391,1.0584391 0 0 0 -0.0059,-0.008 L 3.5722246,125.7752 a 1.0584391,1.0584391 0 0 0 -0.015625,-0.0156 c 0,0 -0.8017392,-0.76344 -1.9902344,-1.27344 -1.39939552,-0.6005 -2.8417968,-0.53711 -2.8417968,-0.53711 l 0.021484,-0.002 z"
|
||||
id="path890" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.11666656;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m -29.632812,126.06445 h 28.3789058 a 1.0584391,1.0584391 0 0 0 0.021484,0 c 0,0 1.13480448,0.011 1.96484378,0.36719 0.79889772,0.34282 1.36536982,0.86176 1.36914062,0.86524 1.25e-5,1e-5 0.00391,0.004 0.00391,0.004 l 9.3671868,9.18945 c 0,0 0.564354,0.59582 0.837891,1.20899 0.220779,0.49491 0.234375,1.40039 0.234375,1.40039 a 1.0584391,1.0584391 0 0 0 -0.002,0.0449 v 40.74609 c 0,2.41592 -1.910258,4.32813 -4.3261717,4.32813 H -29.632812 c -2.415914,0 -4.326172,-1.91209 -4.326172,-4.32813 v -49.49804 c 0,-2.41603 1.910258,-4.32813 4.326172,-4.32813 z"
|
||||
id="rect2684" />
|
||||
<path
|
||||
sodipodi:nodetypes="scccscccscccccssscacccsccccccccccccccccccccaccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -23.40766,161.09299 c -1.45669,-1.45669 0.11934,-3.45839 4.39648,-5.58397 l 2.69124,-1.33743 1.04845,-2.29399 c 0.57665,-1.26169 1.43729,-3.32036 1.91254,-4.5748 l 0.8641,-2.28082 -0.59546,-1.68793 c -0.73217,-2.07547 -0.99326,-5.19438 -0.52872,-6.31588 0.62923,-1.51909 2.69029,-1.36323 3.50626,0.26515 0.63727,1.27176 0.57212,3.57488 -0.18329,6.47946 l -0.6193,2.38125 0.5455,0.92604 c 0.30003,0.50932 1.1764,1.71867 1.9475,2.68743 l 1.44924,1.80272 1.8033728,-0.23533 c 5.72900399,-0.74758 7.6912472,0.523 7.6912472,2.34476 0,2.29921 -4.4984914,2.48899 -8.2760865,-0.16423 -0.8499666,-0.59698 -1.4336605,-1.19001 -1.4336605,-1.19001 0,0 -2.3665326,0.48178 -3.531704,0.79583 -1.202707,0.32417 -1.80274,0.52719 -3.564509,1.12186 0,0 -0.61814,0.89767 -1.02094,1.55026 -1.49858,2.4279 -3.24833,4.43998 -4.49793,5.1723 -1.3991,0.81993 -2.86584,0.87582 -3.60433,0.13733 z m 2.28605,-0.81668 c 0.81883,-0.50607 2.47616,-2.46625 3.62341,-4.28553 l 0.46449,-0.73658 -2.11497,1.06339 c -3.26655,1.64239 -4.76093,3.19033 -3.98386,4.12664 0.43653,0.52598 0.95874,0.48237 2.01093,-0.16792 z m 21.21809,-5.95578 c 0.80089,-0.56097 0.68463,-1.69142 -0.22082,-2.1472 -0.70466,-0.35471 -1.2726074,-0.42759 -3.1031574,-0.40057 -1.1249,0.0767 -2.9337647,0.3034 -3.2403347,0.37237 0,0 0.993716,0.68678 1.434896,0.93922 0.58731,0.33544 2.0145161,0.95811 3.0565161,1.27706 1.02785,0.31461 1.6224,0.28144 2.0729,-0.0409 z m -8.53152,-3.54594 c -0.4847,-0.50952 -1.30889,-1.57296 -1.83152,-2.3632 -0.68353,-0.89643 -1.02629,-1.52887 -1.02629,-1.52887 0,0 -0.4996,1.60694 -0.90948,2.57394 l -1.27876,3.16076 -0.37075,0.71695 c 0,0 1.971043,-0.64627 2.97389,-0.90822 1.0621668,-0.27744 3.21787,-0.70134 3.21787,-0.70134 z m -2.74938,-11.02573 c 0.12363,-1.0375 0.1761,-2.07346 -0.15724,-2.59587 -0.9246,-1.01077 -2.04057,-0.16787 -1.85154,2.23517 0.0636,0.8084 0.26443,2.19033 0.53292,3.04209 l 0.48817,1.54863 0.34358,-1.16638 c 0.18897,-0.64151 0.47882,-2.02015 0.64411,-3.06364 z"
|
||||
style="fill:#ff2116;fill-opacity:1;stroke-width:0.26458335"
|
||||
id="path2697" />
|
||||
<g
|
||||
id="g858">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path845"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Franklin Gothic Medium Cond';-inkscape-font-specification:'Franklin Gothic Medium Cond';letter-spacing:0px;word-spacing:4.26000023px;fill:#2c2c2c;fill-opacity:1;stroke:none;stroke-width:0.35824656px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m -20.930423,167.83862 h 2.364986 q 1.133514,0 1.840213,0.2169 0.706698,0.20991 1.189489,0.9446 0.482795,0.72769 0.482795,1.75625 0,0.94459 -0.391832,1.6233 -0.391833,0.67871 -1.056548,0.97958 -0.65772,0.30087 -2.02913,0.30087 h -0.818651 v 3.72941 h -1.581322 z m 1.581322,1.22447 v 3.33058 h 0.783664 q 1.049552,0 1.44838,-0.39184 0.405826,-0.39183 0.405826,-1.27345 0,-0.65772 -0.265887,-1.06355 -0.265884,-0.41282 -0.587747,-0.50378 -0.314866,-0.098 -1.000572,-0.098 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path847"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Franklin Gothic Medium Cond';-inkscape-font-specification:'Franklin Gothic Medium Cond';letter-spacing:0px;word-spacing:4.26000023px;fill:#2c2c2c;fill-opacity:1;stroke:none;stroke-width:0.35824656px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m -13.842461,167.83862 h 2.148082 q 1.560333,0 2.4909318,0.55276 0.9375993,0.55276 1.4133973,1.6443 0.482791,1.09153 0.482791,2.42096 0,1.3994 -0.4338151,2.49793 -0.4268149,1.09153 -1.3154348,1.76324 -0.8816233,0.67172 -2.5189212,0.67172 h -2.267031 z m 1.581326,1.26645 v 7.018 h 0.657715 q 1.378411,0 2.001144,-0.9516 0.6227329,-0.95858 0.6227329,-2.5539 0,-3.5125 -2.6238769,-3.5125 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path849"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Franklin Gothic Medium Cond';-inkscape-font-specification:'Franklin Gothic Medium Cond';letter-spacing:0px;word-spacing:4.26000023px;fill:#2c2c2c;fill-opacity:1;stroke:none;stroke-width:0.35824656px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m -5.7889096,167.83862 h 5.30372941 v 1.26645 H -4.2075842 v 2.85478 h 2.9807225 v 1.26646 h -2.9807225 v 4.16322 h -1.5813254 z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,62 @@
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.Previewer;
|
||||
using QuestPDF.ReportSample;
|
||||
using QuestPDF.ReportSample.Layouts;
|
||||
|
||||
//ImagePlaceholder.Solid = true;
|
||||
|
||||
// var model = DataSource.GetReport();
|
||||
// var report = new StandardReport(model);
|
||||
// report.ShowInPreviewer();
|
||||
//
|
||||
// return;
|
||||
|
||||
Document
|
||||
.Create(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A4);
|
||||
page.Margin(2, Unit.Centimetre);
|
||||
page.PageColor(Colors.White);
|
||||
page.DefaultTextStyle(x => x.FontSize(20));
|
||||
|
||||
page.Header()
|
||||
.Text("Hot Reload!")
|
||||
.SemiBold().FontSize(36).FontColor(Colors.Blue.Darken2);
|
||||
|
||||
page.Content()
|
||||
.PaddingVertical(1, Unit.Centimetre)
|
||||
.Column(x =>
|
||||
{
|
||||
x.Spacing(20);
|
||||
|
||||
x.Item().Table(t =>
|
||||
{
|
||||
t.ColumnsDefinition(c =>
|
||||
{
|
||||
c.RelativeColumn();
|
||||
c.RelativeColumn(3);
|
||||
});
|
||||
|
||||
t.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Text("Visual Studio");
|
||||
t.Cell().Border(1).Padding(5).Text("Start in debug mode with 'Hot Reload on Save' enabled.");
|
||||
t.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Text("Command line");
|
||||
t.Cell().Border(1).Padding(5).Text("Run 'dotnet watch'.");
|
||||
});
|
||||
|
||||
x.Item().Text("Modify this line and the preview should show your changes instantly.");
|
||||
});
|
||||
|
||||
page.Footer()
|
||||
.AlignCenter()
|
||||
.Text(x =>
|
||||
{
|
||||
x.Span("Page ");
|
||||
x.CurrentPageNumber();
|
||||
});
|
||||
});
|
||||
})
|
||||
.ShowInPreviewer();
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QuestPDF.ReportSample\QuestPDF.ReportSample.csproj" />
|
||||
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Previewer;
|
||||
|
||||
class CommunicationService
|
||||
{
|
||||
public static CommunicationService Instance { get; } = new ();
|
||||
|
||||
public event Action<ICollection<PreviewPage>>? OnDocumentRefreshed;
|
||||
|
||||
private WebApplication? Application { get; set; }
|
||||
|
||||
private readonly JsonSerializerOptions JsonSerializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
private CommunicationService()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Task Start(int port)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.Services.AddLogging(x => x.ClearProviders());
|
||||
builder.WebHost.UseKestrel(options => options.Limits.MaxRequestBodySize = null);
|
||||
Application = builder.Build();
|
||||
|
||||
Application.MapGet("ping", HandlePing);
|
||||
Application.MapGet("version", HandleVersion);
|
||||
Application.MapPost("update/preview", HandleUpdatePreview);
|
||||
|
||||
return Application.RunAsync($"http://localhost:{port}/");
|
||||
}
|
||||
|
||||
public async Task Stop()
|
||||
{
|
||||
await Application.StopAsync();
|
||||
await Application.DisposeAsync();
|
||||
}
|
||||
|
||||
private async Task<IResult> HandlePing()
|
||||
{
|
||||
return OnDocumentRefreshed == null
|
||||
? Results.StatusCode(StatusCodes.Status503ServiceUnavailable)
|
||||
: Results.Ok();
|
||||
}
|
||||
|
||||
private async Task<IResult> HandleVersion()
|
||||
{
|
||||
return Results.Json(GetType().Assembly.GetName().Version);
|
||||
}
|
||||
|
||||
private async Task<IResult> HandleUpdatePreview(HttpRequest request)
|
||||
{
|
||||
var command = JsonSerializer.Deserialize<DocumentSnapshot>(request.Form["command"], JsonSerializerOptions);
|
||||
|
||||
var pages = command
|
||||
.Pages
|
||||
.Select(page =>
|
||||
{
|
||||
using var stream = request.Form.Files[page.Id].OpenReadStream();
|
||||
var picture = SKPicture.Deserialize(stream);
|
||||
|
||||
return new PreviewPage(picture, page.Width, page.Height);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
Task.Run(() => OnDocumentRefreshed(pages));
|
||||
return Results.Ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Previewer;
|
||||
|
||||
class Helpers
|
||||
{
|
||||
public static void GeneratePdfFromDocumentSnapshots(string filePath, ICollection<PreviewPage> pages)
|
||||
{
|
||||
using var stream = File.Create(filePath);
|
||||
|
||||
using var document = SKDocument.CreatePdf(stream);
|
||||
|
||||
foreach (var page in pages)
|
||||
{
|
||||
using var canvas = document.BeginPage(page.Width, page.Height);
|
||||
canvas.DrawPicture(page.Picture);
|
||||
document.EndPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Avalonia.Skia;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Previewer;
|
||||
|
||||
class InteractiveCanvas : ICustomDrawOperation
|
||||
{
|
||||
public Rect Bounds { get; set; }
|
||||
public ICollection<PreviewPage> Pages { get; set; }
|
||||
|
||||
private float Width => (float)Bounds.Width;
|
||||
private float Height => (float)Bounds.Height;
|
||||
|
||||
public float Scale { get; private set; } = 1;
|
||||
public float TranslateX { get; set; }
|
||||
public float TranslateY { get; set; }
|
||||
|
||||
private const float MinScale = 0.1f;
|
||||
private const float MaxScale = 10f;
|
||||
|
||||
private const float PageSpacing = 25f;
|
||||
private const float SafeZone = 25f;
|
||||
|
||||
public float TotalPagesHeight => Pages.Sum(x => x.Height) + (Pages.Count - 1) * PageSpacing;
|
||||
public float TotalHeight => TotalPagesHeight + SafeZone * 2 / Scale;
|
||||
public float MaxWidth => Pages.Any() ? Pages.Max(x => x.Width) : 0;
|
||||
|
||||
public float MaxTranslateY => TotalHeight - Height / Scale;
|
||||
|
||||
public float ScrollPercentY
|
||||
{
|
||||
get
|
||||
{
|
||||
return TranslateY / MaxTranslateY;
|
||||
}
|
||||
set
|
||||
{
|
||||
TranslateY = value * MaxTranslateY;
|
||||
}
|
||||
}
|
||||
|
||||
public float ScrollViewportSizeY
|
||||
{
|
||||
get
|
||||
{
|
||||
var viewPortSize = Height / Scale / TotalHeight;
|
||||
return Math.Clamp(viewPortSize, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#region transformations
|
||||
|
||||
private void LimitScale()
|
||||
{
|
||||
Scale = Math.Max(Scale, MinScale);
|
||||
Scale = Math.Min(Scale, MaxScale);
|
||||
}
|
||||
|
||||
private void LimitTranslate()
|
||||
{
|
||||
if (TotalPagesHeight > Height / Scale)
|
||||
{
|
||||
TranslateY = Math.Min(TranslateY, MaxTranslateY);
|
||||
TranslateY = Math.Max(TranslateY, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslateY = (TotalPagesHeight - Height / Scale) / 2;
|
||||
}
|
||||
|
||||
if (Width / Scale < MaxWidth)
|
||||
{
|
||||
var maxTranslateX = (Width / 2 - SafeZone) / Scale - MaxWidth / 2;
|
||||
|
||||
TranslateX = Math.Min(TranslateX, -maxTranslateX);
|
||||
TranslateX = Math.Max(TranslateX, maxTranslateX);
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslateX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void TranslateWithCurrentScale(float x, float y)
|
||||
{
|
||||
TranslateX += x / Scale;
|
||||
TranslateY += y / Scale;
|
||||
|
||||
LimitTranslate();
|
||||
}
|
||||
|
||||
public void ZoomToPoint(float x, float y, float factor)
|
||||
{
|
||||
var oldScale = Scale;
|
||||
Scale *= factor;
|
||||
|
||||
LimitScale();
|
||||
|
||||
TranslateX -= x / Scale - x / oldScale;
|
||||
TranslateY -= y / Scale - y / oldScale;
|
||||
|
||||
LimitTranslate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region rendering
|
||||
|
||||
public void Render(IDrawingContextImpl context)
|
||||
{
|
||||
if (Pages.Count <= 0)
|
||||
return;
|
||||
|
||||
LimitScale();
|
||||
LimitTranslate();
|
||||
|
||||
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas;
|
||||
|
||||
if (canvas == null)
|
||||
throw new InvalidOperationException($"Context needs to be ISkiaDrawingContextImpl but got {nameof(context)}");
|
||||
|
||||
var originalMatrix = canvas.TotalMatrix;
|
||||
|
||||
canvas.Translate(Width / 2, 0);
|
||||
|
||||
canvas.Scale(Scale);
|
||||
canvas.Translate(TranslateX, -TranslateY + SafeZone / Scale);
|
||||
|
||||
foreach (var page in Pages)
|
||||
{
|
||||
canvas.Translate(-page.Width / 2f, 0);
|
||||
DrawBlankPage(canvas, page.Width, page.Height);
|
||||
canvas.DrawPicture(page.Picture);
|
||||
canvas.Translate(page.Width / 2f, page.Height + PageSpacing);
|
||||
}
|
||||
|
||||
canvas.SetMatrix(originalMatrix);
|
||||
DrawInnerGradient(canvas);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
public bool Equals(ICustomDrawOperation? other) => false;
|
||||
public bool HitTest(Point p) => true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region blank page
|
||||
|
||||
private static SKPaint BlankPagePaint = new SKPaint
|
||||
{
|
||||
Color = SKColors.White
|
||||
};
|
||||
|
||||
private static SKPaint BlankPageShadowPaint = new SKPaint
|
||||
{
|
||||
ImageFilter = SKImageFilter.CreateBlendMode(
|
||||
SKBlendMode.Overlay,
|
||||
SKImageFilter.CreateDropShadowOnly(0, 6, 6, 6, SKColors.Black.WithAlpha(64)),
|
||||
SKImageFilter.CreateDropShadowOnly(0, 10, 14, 14, SKColors.Black.WithAlpha(32)))
|
||||
};
|
||||
|
||||
private void DrawBlankPage(SKCanvas canvas, float width, float height)
|
||||
{
|
||||
canvas.DrawRect(0, 0, width, height, BlankPageShadowPaint);
|
||||
canvas.DrawRect(0, 0, width, height, BlankPagePaint);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region inner viewport gradient
|
||||
|
||||
private const int InnerGradientSize = (int)SafeZone;
|
||||
private static readonly SKColor InnerGradientColor = SKColor.Parse("#666");
|
||||
|
||||
private void DrawInnerGradient(SKCanvas canvas)
|
||||
{
|
||||
// gamma correction
|
||||
var colors = Enumerable
|
||||
.Range(0, InnerGradientSize)
|
||||
.Select(x => 1f - x / (float) InnerGradientSize)
|
||||
.Select(x => Math.Pow(x, 2f))
|
||||
.Select(x => (byte)(x * 255))
|
||||
.Select(x => InnerGradientColor.WithAlpha(x))
|
||||
.ToArray();
|
||||
|
||||
using var fogPaint = new SKPaint
|
||||
{
|
||||
Shader = SKShader.CreateLinearGradient(
|
||||
new SKPoint(0, 0),
|
||||
new SKPoint(0, InnerGradientSize),
|
||||
colors,
|
||||
SKShaderTileMode.Clamp)
|
||||
};
|
||||
|
||||
canvas.DrawRect(0, 0, Width, InnerGradientSize, fogPaint);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Previewer
|
||||
{
|
||||
record PreviewPage(SKPicture Picture, float Width, float Height);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<Application x:Class="QuestPDF.Previewer.PreviewerApp"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Name="QuestPDF Document Preview">
|
||||
<Application.Styles>
|
||||
<FluentTheme Mode="Dark" />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -0,0 +1,27 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace QuestPDF.Previewer
|
||||
{
|
||||
internal class PreviewerApp : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new PreviewerWindow()
|
||||
{
|
||||
DataContext = new PreviewerWindowViewModel()
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace QuestPDF.Previewer
|
||||
{
|
||||
class PreviewerControl : Control
|
||||
{
|
||||
private InteractiveCanvas InteractiveCanvas { get; set; } = new ();
|
||||
|
||||
public static readonly StyledProperty<ObservableCollection<PreviewPage>> PagesProperty =
|
||||
AvaloniaProperty.Register<PreviewerControl, ObservableCollection<PreviewPage>>(nameof(Pages));
|
||||
|
||||
public ObservableCollection<PreviewPage>? Pages
|
||||
{
|
||||
get => GetValue(PagesProperty);
|
||||
set => SetValue(PagesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<float> CurrentScrollProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(CurrentScroll));
|
||||
|
||||
public float CurrentScroll
|
||||
{
|
||||
get => GetValue(CurrentScrollProperty);
|
||||
set => SetValue(CurrentScrollProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<float> ScrollViewportSizeProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(ScrollViewportSize));
|
||||
|
||||
public float ScrollViewportSize
|
||||
{
|
||||
get => GetValue(ScrollViewportSizeProperty);
|
||||
set => SetValue(ScrollViewportSizeProperty, value);
|
||||
}
|
||||
|
||||
public PreviewerControl()
|
||||
{
|
||||
PagesProperty.Changed.Subscribe(x =>
|
||||
{
|
||||
InteractiveCanvas.Pages = x.NewValue.Value;
|
||||
InvalidateVisual();
|
||||
});
|
||||
|
||||
CurrentScrollProperty.Changed.Subscribe(x =>
|
||||
{
|
||||
InteractiveCanvas.ScrollPercentY = x.NewValue.Value;
|
||||
InvalidateVisual();
|
||||
});
|
||||
|
||||
ClipToBounds = true;
|
||||
}
|
||||
|
||||
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
|
||||
{
|
||||
base.OnPointerWheelChanged(e);
|
||||
|
||||
if ((e.KeyModifiers & KeyModifiers.Control) != 0)
|
||||
{
|
||||
var scaleFactor = 1 + e.Delta.Y / 10f;
|
||||
var point = new Point(Bounds.Center.X, Bounds.Top) - e.GetPosition(this);
|
||||
|
||||
InteractiveCanvas.ZoomToPoint((float)point.X, -(float)point.Y, (float)scaleFactor);
|
||||
}
|
||||
|
||||
if (e.KeyModifiers == KeyModifiers.None)
|
||||
{
|
||||
var translation = (float)e.Delta.Y * 25;
|
||||
InteractiveCanvas.TranslateWithCurrentScale(0, -translation);
|
||||
}
|
||||
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private bool IsMousePressed { get; set; }
|
||||
private Vector MousePosition { get; set; }
|
||||
|
||||
protected override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerMoved(e);
|
||||
|
||||
if (IsMousePressed)
|
||||
{
|
||||
var currentPosition = e.GetPosition(this);
|
||||
var translation = currentPosition - MousePosition;
|
||||
InteractiveCanvas.TranslateWithCurrentScale((float)translation.X, -(float)translation.Y);
|
||||
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
MousePosition = e.GetPosition(this);
|
||||
}
|
||||
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
IsMousePressed = true;
|
||||
}
|
||||
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
IsMousePressed = false;
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
CurrentScroll = InteractiveCanvas.ScrollPercentY;
|
||||
ScrollViewportSize = InteractiveCanvas.ScrollViewportSizeY;
|
||||
|
||||
InteractiveCanvas.Bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
|
||||
|
||||
context.Custom(InteractiveCanvas);
|
||||
base.Render(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Previewer;
|
||||
|
||||
internal class DocumentSnapshot
|
||||
{
|
||||
public ICollection<PageSnapshot> Pages { get; set; }
|
||||
|
||||
public class PageSnapshot
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public float Width { get; set; }
|
||||
public float Height { get; set; }
|
||||
|
||||
public SKPicture Picture { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:previewer="clr-namespace:QuestPDF.Previewer"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="QuestPDF.Previewer.PreviewerWindow"
|
||||
x:DataType="previewer:PreviewerWindowViewModel"
|
||||
x:CompileBindings="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="true"
|
||||
ExtendClientAreaTitleBarHeightHint="-1"
|
||||
Background="#666"
|
||||
Icon="/Resources/Logo.png"
|
||||
UseLayoutRounding="True"
|
||||
Title="QuestPDF Document Preview">
|
||||
|
||||
<Window.Styles>
|
||||
<Style Selector="Button.actions">
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
<Setter Property="CornerRadius" Value="100"/>
|
||||
<Setter Property="Background" Value="#888"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="#999"/>
|
||||
</Style>
|
||||
</Window.Styles>
|
||||
|
||||
<Panel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
TextAlignment="Center" Text="QuestPDF Previewer" FontSize="14" Foreground="#DFFF" FontWeight="Regular" IsHitTestVisible="False" />
|
||||
|
||||
<previewer:PreviewerControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
CurrentScroll="{Binding CurrentScroll, Mode=TwoWay}"
|
||||
ScrollViewportSize="{Binding ScrollViewportSize, Mode=OneWayToSource}"
|
||||
Pages="{Binding Pages, Mode=OneWay}" />
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Vertical" VerticalAlignment="Bottom" Spacing="16" Margin="32">
|
||||
<Button Classes="actions"
|
||||
Command="{Binding ShowPdfCommand, Mode=OneTime}"
|
||||
IsVisible="{Binding !!Pages.Count}"
|
||||
ToolTip.Tip="Generates PDF file and shows it in the default browser. Useful for testing compatibility and interactive links.">
|
||||
<Viewbox Width="24" Height="24">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="White" Data="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H13C12.59,21.75 12.2,21.44 11.86,21.1C11.53,20.77 11.25,20.4 11,20H6V4H13V9H18V10.18C18.71,10.34 19.39,10.61 20,11V8L14,2M20.31,18.9C21.64,16.79 21,14 18.91,12.68C16.8,11.35 14,12 12.69,14.08C11.35,16.19 12,18.97 14.09,20.3C15.55,21.23 17.41,21.23 18.88,20.32L22,23.39L23.39,22L20.31,18.9M16.5,19A2.5,2.5 0 0,1 14,16.5A2.5,2.5 0 0,1 16.5,14A2.5,2.5 0 0,1 19,16.5A2.5,2.5 0 0,1 16.5,19Z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button Classes="actions"
|
||||
Command="{Binding ShowDocumentationCommand, Mode=OneTime}"
|
||||
ToolTip.Tip="Opens official QuestPDF documentation">
|
||||
<Viewbox Width="24" Height="24">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="White" Data="M19 1L14 6V17L19 12.5V1M21 5V18.5C19.9 18.15 18.7 18 17.5 18C15.8 18 13.35 18.65 12 19.5V6C10.55 4.9 8.45 4.5 6.5 4.5C4.55 4.5 2.45 4.9 1 6V20.65C1 20.9 1.25 21.15 1.5 21.15C1.6 21.15 1.65 21.1 1.75 21.1C3.1 20.45 5.05 20 6.5 20C8.45 20 10.55 20.4 12 21.5C13.35 20.65 15.8 20 17.5 20C19.15 20 20.85 20.3 22.25 21.05C22.35 21.1 22.4 21.1 22.5 21.1C22.75 21.1 23 20.85 23 20.6V6C22.4 5.55 21.75 5.25 21 5M10 18.41C8.75 18.09 7.5 18 6.5 18C5.44 18 4.18 18.19 3 18.5V7.13C3.91 6.73 5.14 6.5 6.5 6.5C7.86 6.5 9.09 6.73 10 7.13V18.41Z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button Classes="actions"
|
||||
Command="{Binding SponsorProjectCommand, Mode=OneTime}"
|
||||
ToolTip.Tip="Do you like QuestPDF? Please consider sponsoring the project. It really helps!">
|
||||
<Viewbox Width="24" Height="24">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="White" Data="M12,21.1L10.5,22.4C3.9,16.5 0.5,13.4 0.5,9.6C0.5,8.4 0.9,7.3 1.5,6.4C1.5,6.6 1.5,6.8 1.5,7C1.5,11.7 5.4,15.2 12,21.1M13.6,17C18.3,12.7 21.5,9.9 21.6,7C21.6,5 20.1,3.5 18.1,3.5C16.5,3.5 15,4.5 14.5,5.9H12.6C12,4.5 10.5,3.5 9,3.5C7,3.5 5.5,5 5.5,7C5.5,9.9 8.6,12.7 13.4,17L13.5,17.1M18,1.5C21.1,1.5 23.5,3.9 23.5,7C23.5,10.7 20.1,13.8 13.5,19.8C6.9,13.9 3.5,10.8 3.5,7C3.5,3.9 5.9,1.5 9,1.5C10.7,1.5 12.4,2.3 13.5,3.6C14.6,2.3 16.3,1.5 18,1.5Z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollBar Grid.Row="1" Grid.Column="1"
|
||||
Orientation="Vertical"
|
||||
AllowAutoHide="False"
|
||||
Minimum="0" Maximum="1"
|
||||
IsVisible="{Binding VerticalScrollbarVisible, Mode=OneWay}"
|
||||
Value="{Binding CurrentScroll, Mode=TwoWay}"
|
||||
ViewportSize="{Binding ScrollViewportSize, Mode=OneWay}"></ScrollBar>
|
||||
</Grid>
|
||||
</Panel>
|
||||
</Window>
|
||||
@@ -0,0 +1,23 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace QuestPDF.Previewer
|
||||
{
|
||||
class PreviewerWindow : Window
|
||||
{
|
||||
public PreviewerWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using ReactiveUI;
|
||||
using Unit = System.Reactive.Unit;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace QuestPDF.Previewer
|
||||
{
|
||||
internal class PreviewerWindowViewModel : ReactiveObject
|
||||
{
|
||||
private ObservableCollection<PreviewPage> _pages = new();
|
||||
public ObservableCollection<PreviewPage> Pages
|
||||
{
|
||||
get => _pages;
|
||||
set => this.RaiseAndSetIfChanged(ref _pages, value);
|
||||
}
|
||||
|
||||
private float _currentScroll;
|
||||
public float CurrentScroll
|
||||
{
|
||||
get => _currentScroll;
|
||||
set => this.RaiseAndSetIfChanged(ref _currentScroll, value);
|
||||
}
|
||||
|
||||
private float _scrollViewportSize;
|
||||
public float ScrollViewportSize
|
||||
{
|
||||
get => _scrollViewportSize;
|
||||
set
|
||||
{
|
||||
this.RaiseAndSetIfChanged(ref _scrollViewportSize, value);
|
||||
VerticalScrollbarVisible = value < 1;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _verticalScrollbarVisible;
|
||||
public bool VerticalScrollbarVisible
|
||||
{
|
||||
get => _verticalScrollbarVisible;
|
||||
private set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _verticalScrollbarVisible, value));
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> ShowPdfCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> ShowDocumentationCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> SponsorProjectCommand { get; }
|
||||
|
||||
public PreviewerWindowViewModel()
|
||||
{
|
||||
CommunicationService.Instance.OnDocumentRefreshed += HandleUpdatePreview;
|
||||
|
||||
ShowPdfCommand = ReactiveCommand.Create(ShowPdf);
|
||||
ShowDocumentationCommand = ReactiveCommand.Create(() => OpenLink("https://www.questpdf.com/documentation/api-reference.html"));
|
||||
SponsorProjectCommand = ReactiveCommand.Create(() => OpenLink("https://github.com/sponsors/QuestPDF"));
|
||||
}
|
||||
|
||||
private void ShowPdf()
|
||||
{
|
||||
var filePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}.pdf");
|
||||
Helpers.GeneratePdfFromDocumentSnapshots(filePath, Pages);
|
||||
|
||||
OpenLink(filePath);
|
||||
}
|
||||
|
||||
private void OpenLink(string path)
|
||||
{
|
||||
using var openBrowserProcess = new Process
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = path
|
||||
}
|
||||
};
|
||||
|
||||
openBrowserProcess.Start();
|
||||
}
|
||||
|
||||
private void HandleUpdatePreview(ICollection<PreviewPage> pages)
|
||||
{
|
||||
var oldPages = Pages;
|
||||
|
||||
Pages.Clear();
|
||||
Pages = new ObservableCollection<PreviewPage>(pages);
|
||||
|
||||
foreach (var page in oldPages)
|
||||
page.Picture.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.ReactiveUI;
|
||||
using QuestPDF.Previewer;
|
||||
|
||||
var applicationPort = GetCommunicationPort();
|
||||
CommunicationService.Instance.Start(applicationPort);
|
||||
|
||||
if(Application.Current?.ApplicationLifetime is ClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new PreviewerWindow()
|
||||
{
|
||||
DataContext = new PreviewerWindowViewModel()
|
||||
};
|
||||
|
||||
desktop.MainWindow.Show();
|
||||
desktop.Start(Array.Empty<string>());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
AppBuilder
|
||||
.Configure(() => new PreviewerApp())
|
||||
.UsePlatformDetect()
|
||||
.UseReactiveUI()
|
||||
.StartWithClassicDesktopLifetime(Array.Empty<string>());
|
||||
|
||||
static int GetCommunicationPort()
|
||||
{
|
||||
const int defaultApplicationPort = 12500;
|
||||
|
||||
var arguments = Environment.GetCommandLineArgs();
|
||||
|
||||
if (arguments.Length < 2)
|
||||
return defaultApplicationPort;
|
||||
|
||||
return int.TryParse(arguments[1], out var port) ? port : defaultApplicationPort;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF.Previewer</PackageId>
|
||||
<Version>2022.8.0</Version>
|
||||
<PackAsTool>true</PackAsTool>
|
||||
<ToolCommandName>questpdf-previewer</ToolCommandName>
|
||||
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
|
||||
<PackageReleaseNotes>Initial release.</PackageReleaseNotes>
|
||||
<LangVersion>10</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageIcon>Logo.png</PackageIcon>
|
||||
<PackageIconUrl>https://www.questpdf.com/images/package-logo.png</PackageIconUrl>
|
||||
<PackageProjectUrl>https://www.questpdf.com/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/QuestPDF/library.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Copyright>Marcin Ziąbek, QuestPDF contributors</Copyright>
|
||||
<PackageTags>pdf report file export generate generation tool create creation render portable document format quest html library converter open source free standard core previewer</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<OutputType>exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Resources\Logo.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Logo.png" />
|
||||
<None Include="Resources\Logo.png">
|
||||
<Pack>true</Pack>
|
||||
<Visible>false</Visible>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Avalonia" Version="0.10.10" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.10" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.10" />
|
||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.10" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
|
||||
<PackageReference Include="ReactiveUI" Version="17.1.50" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.80.4" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,23 @@
|
||||
Install nuget locally (in directory where nupkg file is located)
|
||||
|
||||
```
|
||||
dotnet tool install --global --add-source . QuestPDF.Previewer --global
|
||||
```
|
||||
|
||||
Run on default port
|
||||
|
||||
```
|
||||
questpdf-previewer
|
||||
```
|
||||
|
||||
Run on custom port
|
||||
|
||||
```
|
||||
questpdf-previewer 12500
|
||||
```
|
||||
|
||||
Remove nuget locally
|
||||
|
||||
```
|
||||
dotnet tool uninstall QuestPDF.Previewer --global
|
||||
```
|
||||
@@ -7,9 +7,6 @@ namespace QuestPDF.ReportSample
|
||||
{
|
||||
public static class DataSource
|
||||
{
|
||||
public static int SectionCounter { get; set; }
|
||||
public static int FieldCounter { get; set; }
|
||||
|
||||
public static ReportModel GetReport()
|
||||
{
|
||||
return new ReportModel
|
||||
@@ -18,8 +15,8 @@ namespace QuestPDF.ReportSample
|
||||
HeaderFields = HeaderFields(),
|
||||
|
||||
LogoData = Helpers.GetImage("Logo.png"),
|
||||
Sections = Enumerable.Range(0, 8).Select(x => GenerateSection()).ToList(),
|
||||
Photos = Enumerable.Range(2, 6).Select(x => GetReportPhotos()).ToList()
|
||||
Sections = Enumerable.Range(0, 40).Select(x => GenerateSection()).ToList(),
|
||||
Photos = Enumerable.Range(0, 25).Select(x => GetReportPhotos()).ToList()
|
||||
};
|
||||
|
||||
List<ReportHeaderField> HeaderFields()
|
||||
@@ -52,8 +49,8 @@ namespace QuestPDF.ReportSample
|
||||
ReportSection GenerateSection()
|
||||
{
|
||||
var sectionLength = Helpers.Random.NextDouble() > 0.75
|
||||
? Helpers.Random.Next(10, 20)
|
||||
: Helpers.Random.Next(3, 11);
|
||||
? Helpers.Random.Next(20, 40)
|
||||
: Helpers.Random.Next(5, 10);
|
||||
|
||||
return new ReportSection
|
||||
{
|
||||
@@ -89,7 +86,6 @@ namespace QuestPDF.ReportSample
|
||||
return new ReportSectionMap
|
||||
{
|
||||
Label = "Location",
|
||||
ImageSource = Placeholders.Image,
|
||||
Location = Helpers.RandomLocation()
|
||||
};
|
||||
}
|
||||
@@ -99,11 +95,7 @@ namespace QuestPDF.ReportSample
|
||||
return new ReportSectionPhotos
|
||||
{
|
||||
Label = "Photos",
|
||||
Photos = Enumerable
|
||||
.Range(0, Helpers.Random.Next(1, 10))
|
||||
.Select(x => Helpers.Random.Next(0, 128))
|
||||
.Select(x => Placeholders.Image(400, 300))
|
||||
.ToList()
|
||||
PhotoCount = Helpers.Random.Next(1, 15)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,14 +103,9 @@ namespace QuestPDF.ReportSample
|
||||
{
|
||||
return new ReportPhoto()
|
||||
{
|
||||
PhotoData = Placeholders.Image(400, 300),
|
||||
|
||||
Comments = Placeholders.Sentence(),
|
||||
Date = DateTime.Now - TimeSpan.FromDays(Helpers.Random.NextDouble() * 100),
|
||||
Location = Helpers.RandomLocation(),
|
||||
|
||||
MapContextSource = x => Placeholders.Image(400, 300),
|
||||
MapDetailsSource = x => Placeholders.Image(400, 300)
|
||||
Location = Helpers.RandomLocation()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -6,7 +7,7 @@ namespace QuestPDF.ReportSample
|
||||
{
|
||||
public static class Helpers
|
||||
{
|
||||
public static Random Random { get; } = new Random();
|
||||
public static Random Random { get; } = new Random(1);
|
||||
|
||||
public static string GetTestItem(string path) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", path);
|
||||
|
||||
@@ -24,5 +25,32 @@ namespace QuestPDF.ReportSample
|
||||
Latitude = Helpers.Random.NextDouble() * 180f - 90f
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<int, string> RomanNumeralCache = new ConcurrentDictionary<int, string>();
|
||||
|
||||
public static string FormatAsRomanNumeral(this int number)
|
||||
{
|
||||
if (number < 0 || number > 3999)
|
||||
throw new ArgumentOutOfRangeException("Number should be in range from 1 to 3999");
|
||||
|
||||
return RomanNumeralCache.GetOrAdd(number, x =>
|
||||
{
|
||||
if (x >= 1000) return "M" + FormatAsRomanNumeral(x - 1000);
|
||||
if (x >= 900) return "CM" + FormatAsRomanNumeral(x - 900);
|
||||
if (x >= 500) return "D" + FormatAsRomanNumeral(x - 500);
|
||||
if (x >= 400) return "CD" + FormatAsRomanNumeral(x - 400);
|
||||
if (x >= 100) return "C" + FormatAsRomanNumeral(x - 100);
|
||||
if (x >= 90) return "XC" + FormatAsRomanNumeral(x - 90);
|
||||
if (x >= 50) return "L" + FormatAsRomanNumeral(x - 50);
|
||||
if (x >= 40) return "XL" + FormatAsRomanNumeral(x - 40);
|
||||
if (x >= 10) return "X" + FormatAsRomanNumeral(x - 10);
|
||||
if (x >= 9) return "IX" + FormatAsRomanNumeral(x - 9);
|
||||
if (x >= 5) return "V" + FormatAsRomanNumeral(x - 5);
|
||||
if (x >= 4) return "IV" + FormatAsRomanNumeral(x - 4);
|
||||
if (x >= 1) return "I" + FormatAsRomanNumeral(x - 1);
|
||||
|
||||
return string.Empty;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
public class DifferentHeadersTemplate : IDocument
|
||||
{
|
||||
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container
|
||||
.Page(page =>
|
||||
{
|
||||
page.Margin(40);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Header().Element(ComposeHeader);
|
||||
page.Content().Element(ComposeContent);
|
||||
page.Footer().Element(ComposeFooter);
|
||||
});
|
||||
}
|
||||
|
||||
private void ComposeHeader(IContainer container)
|
||||
{
|
||||
container.Background(Colors.Grey.Lighten3).Border(1).Column(column =>
|
||||
{
|
||||
column.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);
|
||||
});
|
||||
column.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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void ComposeContent(IContainer container)
|
||||
{
|
||||
container.Column(column =>
|
||||
{
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
private void ComposeFooter(IContainer container)
|
||||
{
|
||||
container.Background(Colors.Grey.Lighten3).Column(column =>
|
||||
{
|
||||
column.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Text(x =>
|
||||
{
|
||||
x.CurrentPageNumber();
|
||||
x.Span(" / ");
|
||||
x.TotalPages();
|
||||
});
|
||||
row.RelativeItem().AlignRight().Text("Footer for header");
|
||||
});
|
||||
|
||||
column.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Text(x =>
|
||||
{
|
||||
x.CurrentPageNumber();
|
||||
x.Span(" / ");
|
||||
x.TotalPages();
|
||||
});
|
||||
row.RelativeItem().AlignRight().Text("Footer for every page except header");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
public class ImagePlaceholder : IComponent
|
||||
{
|
||||
public static bool Solid { get; set; } = false;
|
||||
|
||||
public void Compose(IContainer container)
|
||||
{
|
||||
if (Solid)
|
||||
container.Background(Placeholders.Color());
|
||||
|
||||
else
|
||||
container.Image(Placeholders.Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
public class ImageTemplate : IComponent
|
||||
{
|
||||
private Func<Size, byte[]> Source { get; }
|
||||
private float AspectRatio { get; }
|
||||
|
||||
public ImageTemplate(byte[] source, float aspectRatio = 1.333333f) : this(_ => source, aspectRatio)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ImageTemplate(Func<Size, byte[]> source, float aspectRatio = 1.333333f)
|
||||
{
|
||||
Source = source;
|
||||
AspectRatio = aspectRatio;
|
||||
}
|
||||
|
||||
public void Compose(IContainer container)
|
||||
{
|
||||
container
|
||||
.AspectRatio(AspectRatio)
|
||||
.Background("#EEEEEE")
|
||||
.Image(Source(Size.Zero));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -17,11 +18,11 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
container
|
||||
.ShowEntire()
|
||||
.Stack(stack =>
|
||||
.Column(column =>
|
||||
{
|
||||
stack.Spacing(5);
|
||||
stack.Item(PhotoWithMaps);
|
||||
stack.Item(PhotoDetails);
|
||||
column.Spacing(5);
|
||||
column.Item().Element(PhotoWithMaps);
|
||||
column.Item().Element(PhotoDetails);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,14 +31,14 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
container
|
||||
.Row(row =>
|
||||
{
|
||||
row.RelativeColumn(2).AspectRatio(4 / 3f).Image(Placeholders.Image);
|
||||
row.RelativeItem(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
|
||||
row.RelativeColumn().PaddingLeft(5).Stack(stack =>
|
||||
row.RelativeItem().PaddingLeft(5).Column(column =>
|
||||
{
|
||||
stack.Spacing(7f);
|
||||
column.Spacing(7f);
|
||||
|
||||
stack.Item().AspectRatio(4 / 3f).Image(Placeholders.Image);
|
||||
stack.Item().AspectRatio(4 / 3f).Image(Placeholders.Image);
|
||||
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -47,14 +48,14 @@ 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");
|
||||
grid.Item(2).ValueCell().Text(Model.Location.Format());
|
||||
|
||||
grid.Element().LabelCell().Text("Date", Typography.Normal);
|
||||
grid.Element(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty, Typography.Normal);
|
||||
grid.Element().LabelCell().Text("Location", Typography.Normal);
|
||||
grid.Element(2).ValueCell().Text(Model.Location.Format(), Typography.Normal);
|
||||
|
||||
grid.Element().LabelCell().Text("Comments", Typography.Normal);
|
||||
grid.Element(5).ValueCell().Text(Model.Comments, Typography.Normal);
|
||||
grid.Item().LabelCell().Text("Comments");
|
||||
grid.Item(5).ValueCell().Text(Model.Comments);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -17,28 +18,29 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
container
|
||||
.EnsureSpace()
|
||||
.Decoration(section =>
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
section
|
||||
.Header()
|
||||
decoration
|
||||
.Before()
|
||||
.PaddingBottom(5)
|
||||
.Text(Model.Title, Typography.Headline);
|
||||
.Text(Model.Title)
|
||||
.Style(Typography.Headline);
|
||||
|
||||
section.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack =>
|
||||
decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Column(column =>
|
||||
{
|
||||
foreach (var part in Model.Parts)
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
column.Item().EnsureSpace(25).Row(row =>
|
||||
{
|
||||
row.ConstantColumn(150).LabelCell().Text(part.Label, Typography.Normal);
|
||||
var frame = row.RelativeColumn().ValueCell();
|
||||
row.ConstantItem(150).LabelCell().Text(part.Label);
|
||||
var frame = row.RelativeItem().ValueCell();
|
||||
|
||||
if (part is ReportSectionText text)
|
||||
frame.Text(text.Text, Typography.Normal);
|
||||
|
||||
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));
|
||||
});
|
||||
@@ -49,35 +51,38 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
|
||||
void MapElement(IContainer container, ReportSectionMap model)
|
||||
{
|
||||
if (model.ImageSource == null || model.Location == null)
|
||||
if (model.Location == null)
|
||||
{
|
||||
container.Text("No location provided", Typography.Normal);
|
||||
container.Text("No location provided");
|
||||
return;
|
||||
}
|
||||
|
||||
container.ShowEntire().Stack(stack =>
|
||||
container.ShowEntire().Column(column =>
|
||||
{
|
||||
stack.Spacing(5);
|
||||
column.Spacing(5);
|
||||
|
||||
stack.Item().MaxWidth(250).AspectRatio(4 / 3f).Image(Placeholders.Image);
|
||||
stack.Item().Text(model.Location.Format(), Typography.Normal);
|
||||
column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
column.Item().Text(model.Location.Format());
|
||||
});
|
||||
}
|
||||
|
||||
void PhotosElement(IContainer container, ReportSectionPhotos model)
|
||||
{
|
||||
if (model.Photos.Count == 0)
|
||||
if (model.PhotoCount == 0)
|
||||
{
|
||||
container.Text("No photos", Typography.Normal);
|
||||
container.Text("No photos").Style(Typography.Normal);
|
||||
return;
|
||||
}
|
||||
|
||||
container.Debug("Photo gallery").Grid(grid =>
|
||||
container.DebugArea("Photos").Grid(grid =>
|
||||
{
|
||||
grid.Spacing(5);
|
||||
grid.Columns(3);
|
||||
|
||||
model.Photos.ForEach(x => grid.Element().AspectRatio(4 / 3f).Image(Placeholders.Image));
|
||||
Enumerable
|
||||
.Range(0, model.PhotoCount)
|
||||
.ToList()
|
||||
.ForEach(x => grid.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,49 +18,59 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
return new DocumentMetadata()
|
||||
{
|
||||
Title = Model.Title,
|
||||
Size = PageSizes.A4
|
||||
Title = Model.Title
|
||||
};
|
||||
}
|
||||
|
||||
public void Compose(IContainer container)
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container
|
||||
.PaddingVertical(40)
|
||||
.PaddingHorizontal(50)
|
||||
.Page(page =>
|
||||
{
|
||||
page.Header(ComposeHeader);
|
||||
page.Content(ComposeContent);
|
||||
page.Footer().AlignCenter().PageNumber("Page {number}");
|
||||
page.DefaultTextStyle(Typography.Normal);
|
||||
|
||||
page.MarginVertical(40);
|
||||
page.MarginHorizontal(50);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Header().Element(ComposeHeader);
|
||||
page.Content().Element(ComposeContent);
|
||||
|
||||
page.Footer().AlignCenter().Text(text =>
|
||||
{
|
||||
text.CurrentPageNumber().Format(x => x?.FormatAsRomanNumeral() ?? "-----");
|
||||
text.Span(" / ");
|
||||
text.TotalPages().Format(x => x?.FormatAsRomanNumeral() ?? "-----");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void ComposeHeader(IContainer container)
|
||||
{
|
||||
container.Stack(stack =>
|
||||
container.Column(column =>
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.Spacing(50);
|
||||
|
||||
row.RelativeColumn().PaddingTop(-10).Text(Model.Title, Typography.Title);
|
||||
row.ConstantColumn(150).ExternalLink("https://www.questpdf.com").Image(Model.LogoData);
|
||||
row.RelativeItem().PaddingTop(-10).Text(Model.Title).Style(Typography.Title);
|
||||
row.ConstantItem(90).Hyperlink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
|
||||
});
|
||||
|
||||
stack.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
|
||||
column.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
|
||||
|
||||
stack.Item().ShowOnce().Grid(grid =>
|
||||
column.Item().ShowOnce().Grid(grid =>
|
||||
{
|
||||
grid.Columns(2);
|
||||
grid.Spacing(5);
|
||||
|
||||
foreach (var field in Model.HeaderFields)
|
||||
{
|
||||
grid.Element().Stack(row =>
|
||||
{
|
||||
row.Item().AlignLeft().Text(field.Label, Typography.Normal.SemiBold());
|
||||
row.Item().Text(field.Value, Typography.Normal);
|
||||
grid.Item().Text(text =>
|
||||
{
|
||||
text.Span($"{field.Label}: ").SemiBold();
|
||||
text.Span(field.Value);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -69,21 +79,23 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
|
||||
void ComposeContent(IContainer container)
|
||||
{
|
||||
container.PaddingVertical(20).Stack(stack =>
|
||||
container.PaddingVertical(20).Column(column =>
|
||||
{
|
||||
stack.Spacing(20);
|
||||
|
||||
stack.Item().Component(new TableOfContentsTemplate(Model.Sections));
|
||||
column.Spacing(20);
|
||||
|
||||
column.Item().Component(new TableOfContentsTemplate(Model.Sections));
|
||||
|
||||
column.Item().PageBreak();
|
||||
|
||||
foreach (var section in Model.Sections)
|
||||
stack.Item().Location(section.Title).Component(new SectionTemplate(section));
|
||||
|
||||
stack.Item().PageBreak();
|
||||
stack.Item().Location("Photos");
|
||||
column.Item().Section(section.Title).Component(new SectionTemplate(section));
|
||||
|
||||
column.Item().PageBreak();
|
||||
column.Item().Section("Photos");
|
||||
|
||||
foreach (var photo in Model.Photos)
|
||||
stack.Item().Component(new PhotoTemplate(photo));
|
||||
column.Item().Component(new PhotoTemplate(photo));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.ReportSample.Layouts
|
||||
{
|
||||
@@ -16,21 +19,22 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
public void Compose(IContainer container)
|
||||
{
|
||||
container
|
||||
.Decoration(section =>
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
section
|
||||
.Header()
|
||||
decoration
|
||||
.Before()
|
||||
.PaddingBottom(5)
|
||||
.Text("Table of contents", Typography.Headline);
|
||||
.Text("Table of contents")
|
||||
.Style(Typography.Headline);
|
||||
|
||||
section.Content().Stack(stack =>
|
||||
decoration.Content().Column(column =>
|
||||
{
|
||||
stack.Spacing(5);
|
||||
column.Spacing(5);
|
||||
|
||||
for (var i = 0; i < Sections.Count; i++)
|
||||
stack.Item(c => DrawLink(c, i+1, Sections[i].Title));
|
||||
column.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
|
||||
|
||||
stack.Item(c => DrawLink(c, Sections.Count+1, "Photos"));
|
||||
column.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -38,12 +42,37 @@ namespace QuestPDF.ReportSample.Layouts
|
||||
private void DrawLink(IContainer container, int number, string locationName)
|
||||
{
|
||||
container
|
||||
.InternalLink(locationName)
|
||||
.SectionLink(locationName)
|
||||
.Row(row =>
|
||||
{
|
||||
row.ConstantColumn(25).Text($"{number}.", Typography.Normal);
|
||||
row.RelativeColumn().Text(locationName, Typography.Normal);
|
||||
row.ConstantItem(20).Text($"{number}.");
|
||||
row.AutoItem().Text(locationName);
|
||||
|
||||
row.RelativeItem().PaddingHorizontal(2).AlignBottom().TranslateY(-3).Height(1).Canvas((canvas, space) =>
|
||||
{
|
||||
// best to statically cache
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
StrokeWidth = space.Height,
|
||||
PathEffect = SKPathEffect.CreateDash(new float[] { 1, 3 }, 0)
|
||||
};
|
||||
|
||||
canvas.DrawLine(0, 0, space.Width, 0, paint);
|
||||
});
|
||||
|
||||
row.AutoItem().Text(text =>
|
||||
{
|
||||
text.BeginPageNumberOfSection(locationName);
|
||||
text.Span(" - ");
|
||||
text.EndPageNumberOfSection(locationName);
|
||||
|
||||
var lengthStyle = TextStyle.Default.FontColor(Colors.Grey.Medium);
|
||||
|
||||
text.Span(" (").Style(lengthStyle);
|
||||
text.TotalPagesWithinSection(locationName).Style(lengthStyle).Format(x => x == 1 ? "1 page long" : $"{x} pages long");
|
||||
text.Span(")").Style(lengthStyle);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,22 +44,16 @@ namespace QuestPDF.ReportSample
|
||||
|
||||
public class ReportSectionMap : ReportSectionElement
|
||||
{
|
||||
public Func<Size, byte[]> ImageSource { get; set; }
|
||||
public Location Location { get; set; }
|
||||
}
|
||||
|
||||
public class ReportSectionPhotos : ReportSectionElement
|
||||
{
|
||||
public List<byte[]> Photos { get; set; }
|
||||
public int PhotoCount { get; set; }
|
||||
}
|
||||
|
||||
public class ReportPhoto
|
||||
{
|
||||
public byte[] PhotoData { get; set; }
|
||||
|
||||
public Func<Size, byte[]> MapDetailsSource { get; set; }
|
||||
public Func<Size, byte[]> MapContextSource { get; set; }
|
||||
|
||||
{
|
||||
public Location Location { get; set; }
|
||||
|
||||
public DateTime? Date { get; set; }
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
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.Helpers;
|
||||
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.VisitChildren(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,18 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>8</LangVersion>
|
||||
<RootNamespace>QuestPDF.ReportSample</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DeepCloner" Version="0.10.2" />
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.2" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||
<PackageReference Include="nunit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@@ -3,60 +3,56 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.ReportSample.Layouts;
|
||||
|
||||
namespace QuestPDF.ReportSample
|
||||
{
|
||||
public class ReportGeneration
|
||||
{
|
||||
[Test]
|
||||
public void GenerateAndShow()
|
||||
private StandardReport Report { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var reportModel = DataSource.GetReport();
|
||||
var report = new StandardReport(reportModel);
|
||||
|
||||
var model = DataSource.GetReport();
|
||||
Report = new StandardReport(model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateAndShowPdf()
|
||||
{
|
||||
//ImagePlaceholder.Solid = true;
|
||||
|
||||
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
|
||||
report.GeneratePdf(path);
|
||||
|
||||
Report.GeneratePdf(path);
|
||||
Process.Start("explorer.exe", path);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void PerformanceBenchmark()
|
||||
public void GenerateAndShowXps()
|
||||
{
|
||||
// test size
|
||||
const int testSize = 100;
|
||||
const decimal performanceTarget = 5; // documents per second
|
||||
|
||||
// create report models
|
||||
var reports = Enumerable
|
||||
.Range(0, testSize)
|
||||
.Select(x =>
|
||||
{
|
||||
var reportModel = DataSource.GetReport();
|
||||
return new StandardReport(reportModel);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// generate documents
|
||||
var sw = new Stopwatch();
|
||||
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.xps");
|
||||
Report.GenerateXps(path);
|
||||
Process.Start("explorer.exe", path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Profile()
|
||||
{
|
||||
ImagePlaceholder.Solid = true;
|
||||
|
||||
sw.Start();
|
||||
var totalSize = reports.Select(x => x.GeneratePdf()).Sum(x => (long)x.Length);
|
||||
sw.Stop();
|
||||
|
||||
// show summary
|
||||
Console.WriteLine($"Total size: {totalSize:N0} bytes");
|
||||
var container = new DocumentContainer();
|
||||
Report.Compose(container);
|
||||
var content = container.Compose();
|
||||
|
||||
var performance = sw.ElapsedMilliseconds / (decimal)testSize;
|
||||
var speed = 1000M / performance;
|
||||
Console.WriteLine($"Test time: {sw.ElapsedMilliseconds} ms");
|
||||
Console.WriteLine($"Time per document: {performance:N} ms");
|
||||
Console.WriteLine($"Documents per second: {speed:N} d/s");
|
||||
var metadata = Report.GetMetadata();
|
||||
var pageContext = new PageContext();
|
||||
|
||||
if (speed < performanceTarget)
|
||||
throw new Exception("Rendering algorithm is too slow.");
|
||||
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.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.Calibri).Color(Colors.Black).Size(11).LineHeight(1.25f).AlignLeft();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -10,11 +10,7 @@ namespace QuestPDF.UnitTests
|
||||
public class AlignmentTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new Alignment().MeasureWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Draw_ShouldHandleNullChild() => new Alignment().DrawWithoutChild();
|
||||
|
||||
public void Measure() => SimpleContainerTests.Measure<Alignment>();
|
||||
[Test]
|
||||
public void Draw_HorizontalCenter_VerticalCenter()
|
||||
{
|
||||
@@ -27,7 +23,7 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.DrawElement(new Size(1000, 500))
|
||||
.ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: new PartialRender(new Size(400, 200)))
|
||||
.ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: SpacePlan.PartialRender(new Size(400, 200)))
|
||||
.ExpectCanvasTranslate(new Position(300, 150))
|
||||
.ExpectChildDraw(new Size(400, 200))
|
||||
.ExpectCanvasTranslate(new Position(-300, -150))
|
||||
@@ -46,7 +42,7 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
|
||||
.ExpectCanvasTranslate(new Position(0, 125))
|
||||
.ExpectChildDraw(new Size(100, 50))
|
||||
.ExpectCanvasTranslate(new Position(0, -125))
|
||||
@@ -65,7 +61,7 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
|
||||
.ExpectCanvasTranslate(new Position(150, 250))
|
||||
.ExpectChildDraw(new Size(100, 50))
|
||||
.ExpectCanvasTranslate(new Position(-150, -250))
|
||||
@@ -84,7 +80,7 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
|
||||
.ExpectCanvasTranslate(new Position(300, 0))
|
||||
.ExpectChildDraw(new Size(100, 50))
|
||||
.ExpectCanvasTranslate(new Position(-300, 0))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -9,12 +9,6 @@ namespace QuestPDF.UnitTests
|
||||
[TestFixture]
|
||||
public class AspectRatioTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new AspectRatio().MeasureWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Measure_FitWidth_EnoughSpace_FullRender()
|
||||
{
|
||||
@@ -26,8 +20,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 201))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -41,8 +35,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 201))
|
||||
.ExpectChildMeasure(new Size(400, 200), new PartialRender(100, 50))
|
||||
.CheckMeasureResult(new PartialRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.PartialRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -56,8 +50,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 201))
|
||||
.ExpectChildMeasure(new Size(400, 200), new Wrap())
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -71,8 +65,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 201))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -86,7 +80,7 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 199))
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -100,8 +94,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(401, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -115,7 +109,7 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(399, 200))
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -129,8 +123,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -144,8 +138,8 @@ namespace QuestPDF.UnitTests
|
||||
Ratio = 2f
|
||||
})
|
||||
.MeasureElement(new Size(500, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace QuestPDF.UnitTests
|
||||
public class BackgroundTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new Background().MeasureWithoutChild();
|
||||
|
||||
public void Measure() => SimpleContainerTests.Measure<Background>();
|
||||
|
||||
[Test]
|
||||
public void Draw_ShouldHandleNullChild()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -11,8 +11,8 @@ namespace QuestPDF.UnitTests
|
||||
public class BorderTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new Border().MeasureWithoutChild();
|
||||
|
||||
public void Measure() => SimpleContainerTests.Measure<Border>();
|
||||
|
||||
[Test]
|
||||
public void ComponentShouldNotAffectLayout()
|
||||
{
|
||||
@@ -27,8 +27,8 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
|
||||
.CheckMeasureResult( new FullRender(new Size(100, 50)));
|
||||
.ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))
|
||||
.CheckMeasureResult( SpacePlan.FullRender(new Size(100, 50)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -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<MinimalBox>();
|
||||
|
||||
[Test]
|
||||
public void Draw_Wrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new MinimalBox
|
||||
{
|
||||
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 MinimalBox
|
||||
{
|
||||
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 MinimalBox
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using System.Linq;
|
||||
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 ColumnTests
|
||||
{
|
||||
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)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(300, 200))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(300, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsPartialRender_WhenSecondChildWraps()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
|
||||
.ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(200, 100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(300, 250));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Draw
|
||||
|
||||
[Test]
|
||||
public void Draw_WhenFirstChildWraps()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_WhenFirstChildPartiallyRenders()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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)
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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)
|
||||
.ExpectCanvasTranslate(0, 100)
|
||||
.ExpectChildDraw("second", new Size(400, 150))
|
||||
.ExpectCanvasTranslate(0, -100)
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItems)
|
||||
.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)
|
||||
.ExpectCanvasTranslate(0, 100)
|
||||
.ExpectChildDraw("second", new Size(400, 150))
|
||||
.ExpectCanvasTranslate(0, -100)
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_UsesEmpty_WhenFirstChildIsRendered()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
|
||||
.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)
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
|
||||
.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);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -9,12 +9,8 @@ namespace QuestPDF.UnitTests
|
||||
[TestFixture]
|
||||
public class ConstrainedTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new Constrained().MeasureWithoutChild();
|
||||
#region Height
|
||||
|
||||
[Test]
|
||||
public void Draw_ShouldHandleNullChild() => new Constrained().DrawWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Measure_MinHeight_ExpectWrap()
|
||||
{
|
||||
@@ -24,7 +20,7 @@ namespace QuestPDF.UnitTests
|
||||
MinHeight = 100
|
||||
})
|
||||
.MeasureElement(new Size(400, 50))
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -37,8 +33,8 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(400, 50))
|
||||
.CheckMeasureResult(new FullRender(400, 100));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(400, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -51,8 +47,8 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(400, 150))
|
||||
.CheckMeasureResult(new FullRender(400, 150));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(400, 150))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 150));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -64,7 +60,7 @@ namespace QuestPDF.UnitTests
|
||||
MaxHeight = 100
|
||||
})
|
||||
.MeasureElement(new Size(400, 150))
|
||||
.CheckMeasureResult(new FullRender(0, 0));
|
||||
.CheckMeasureResult(SpacePlan.FullRender(0, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -77,8 +73,8 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 100), new PartialRender(400, 75))
|
||||
.CheckMeasureResult(new PartialRender(400, 75));
|
||||
.ExpectChildMeasure(new Size(400, 100), SpacePlan.PartialRender(400, 75))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(400, 75));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -91,8 +87,94 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 100), new Wrap())
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure(new Size(400, 100), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Width
|
||||
|
||||
[Test]
|
||||
public void Measure_MinWidth_ExpectWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MinWidth = 100
|
||||
})
|
||||
.MeasureElement(new Size(50, 400))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_MinWidth_ExtendHeight()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MinWidth = 100,
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(200, 400))
|
||||
.ExpectChildMeasure(new Size(200, 400), SpacePlan.FullRender(50, 400))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(100, 400));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_MinWidth_PassHeight()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MinWidth = 100,
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(200, 400))
|
||||
.ExpectChildMeasure(new Size(200, 400), SpacePlan.FullRender(150, 400))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(150, 400));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_MaxWidth_Empty()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MaxWidth = 100
|
||||
})
|
||||
.MeasureElement(new Size(150, 400))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(0, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_MaxWidth_PartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MaxWidth = 100,
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(200, 400))
|
||||
.ExpectChildMeasure(new Size(100, 400), SpacePlan.PartialRender(75, 400))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(75, 400));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_MaxWidth_ExpectWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new Constrained
|
||||
{
|
||||
MaxWidth = 100,
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(200, 400))
|
||||
.ExpectChildMeasure(new Size(100, 400), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace QuestPDF.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DebugTests
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -9,125 +9,128 @@ namespace QuestPDF.UnitTests
|
||||
[TestFixture]
|
||||
public class DecorationTests
|
||||
{
|
||||
private Decoration CreateDecoration(TestPlan testPlan)
|
||||
{
|
||||
return new Decoration
|
||||
{
|
||||
Before = testPlan.CreateChild("before"),
|
||||
Content = testPlan.CreateChild("content"),
|
||||
After = testPlan.CreateChild("after"),
|
||||
};
|
||||
}
|
||||
|
||||
#region Measure
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenDecorationReturnsWrap()
|
||||
public void Measure_ReturnsWrap_WhenBeforeReturnsWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new Wrap())
|
||||
.CheckMeasureResult(new Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenDecorationReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new PartialRender(300, 200))
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.Wrap())
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenContentReturnsWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new FullRender(300, 100))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), new Wrap())
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsPartialRender_WhenContentReturnsPartialRender()
|
||||
public void Measure_ReturnsWrap_WhenAfterReturnsWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new FullRender(300, 100))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), new PartialRender(200, 150))
|
||||
.CheckMeasureResult(new PartialRender(400, 250));
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.Wrap())
|
||||
.ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsFullRender_WhenContentReturnsFullRender()
|
||||
public void Measure_ReturnsWrap_WhenBeforeReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new FullRender(300, 100))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), new FullRender(200, 150))
|
||||
.CheckMeasureResult(new FullRender(400, 250));
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.PartialRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenAfterReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.PartialRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenContentReturnsPartialRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(150, 100))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(150, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenContentReturnsFullRender()
|
||||
{
|
||||
TestPlan
|
||||
.For(CreateDecoration)
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(150, 100))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(150, 200));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Draw
|
||||
|
||||
[Test]
|
||||
public void Draw_Prepend()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Prepend,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new 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 SimpleDecoration
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
DecorationElement = x.CreateChild("decoration"),
|
||||
ContentElement = x.CreateChild("content")
|
||||
})
|
||||
.For(CreateDecoration)
|
||||
.DrawElement(new Size(400, 300))
|
||||
.ExpectChildMeasure("decoration", new Size(400, 300), new FullRender(300, 100))
|
||||
.ExpectChildDraw("content", new Size(400, 200))
|
||||
.ExpectCanvasTranslate(0, 200)
|
||||
.ExpectChildDraw("decoration", new Size(400, 100))
|
||||
.ExpectCanvasTranslate(0, -200)
|
||||
.ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(200, 40))
|
||||
.ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(200, 60))
|
||||
.ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(300, 100))
|
||||
|
||||
.ExpectCanvasTranslate(0, 0)
|
||||
.ExpectChildDraw("before", new Size(300, 40))
|
||||
.ExpectCanvasTranslate(0, 0)
|
||||
|
||||
.ExpectCanvasTranslate(0, 40)
|
||||
.ExpectChildDraw("content", new Size(300, 100))
|
||||
.ExpectCanvasTranslate(0, -40)
|
||||
|
||||
.ExpectCanvasTranslate(0, 140)
|
||||
.ExpectChildDraw("after", new Size(300, 60))
|
||||
.ExpectCanvasTranslate(0, -140)
|
||||
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -20,7 +20,7 @@ namespace QuestPDF.UnitTests
|
||||
Source = GenerateImage
|
||||
})
|
||||
.MeasureElement(new Size(300, 200))
|
||||
.CheckMeasureResult(new FullRender(300, 200));
|
||||
.CheckMeasureResult(SpacePlan.FullRender(300, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -51,7 +51,7 @@ namespace QuestPDF.UnitTests
|
||||
[Test]
|
||||
public void Draw_PassesCorrectSizeToSource()
|
||||
{
|
||||
Size passedSize = null;
|
||||
Size passedSize = default;
|
||||
|
||||
TestPlan
|
||||
.For(x => new DynamicImage
|
||||
@@ -66,7 +66,7 @@ namespace QuestPDF.UnitTests
|
||||
.ExpectCanvasDrawImage(Position.Zero, new Size(400, 300))
|
||||
.CheckDrawResult();
|
||||
|
||||
passedSize.Should().Be(new Size(400, 300));
|
||||
passedSize.Should().BeEquivalentTo(new Size(400, 300));
|
||||
}
|
||||
|
||||
byte[] GenerateImage(Size size)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -7,10 +7,10 @@ using QuestPDF.UnitTests.TestEngine;
|
||||
namespace QuestPDF.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class WrapWhenLittleSpaceTests
|
||||
public class EnsureSpaceTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenNotEnoughSpace()
|
||||
public void Measure_ReturnsWrap_WhenChildReturnsWrap()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new EnsureSpace
|
||||
@@ -19,11 +19,26 @@ namespace QuestPDF.UnitTests
|
||||
MinHeight = 200
|
||||
})
|
||||
.MeasureElement(new Size(400, 100))
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure(new Size(400, 100), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_Continues_WhenEnoughSpace()
|
||||
public void Measure_ReturnsWrap_WhenChildReturnsPartialRender_AndNotEnoughSpace()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new EnsureSpace
|
||||
{
|
||||
Child = x.CreateChild(),
|
||||
MinHeight = 200
|
||||
})
|
||||
.MeasureElement(new Size(400, 100))
|
||||
.ExpectChildMeasure(new Size(400, 100), SpacePlan.PartialRender(300, 50))
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsPartialRender_WhenChildReturnsPartialRender_AndEnoughSpace()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new EnsureSpace
|
||||
@@ -32,8 +47,39 @@ namespace QuestPDF.UnitTests
|
||||
MinHeight = 200
|
||||
})
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(new Size(400, 300), new FullRender(300, 250))
|
||||
.CheckMeasureResult(new FullRender(300, 250));
|
||||
.ExpectChildMeasure(new Size(400, 300), SpacePlan.PartialRender(300, 250))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(300, 250));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndNotEnoughSpace()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new EnsureSpace
|
||||
{
|
||||
Child = x.CreateChild(),
|
||||
MinHeight = 200
|
||||
})
|
||||
.MeasureElement(new Size(400, 100))
|
||||
.ExpectChildMeasure(new Size(400, 100), SpacePlan.FullRender(300, 50))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(300, 50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndEnoughSpace()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new EnsureSpace
|
||||
{
|
||||
Child = x.CreateChild(),
|
||||
MinHeight = 200
|
||||
})
|
||||
.MeasureElement(new Size(400, 300))
|
||||
.ExpectChildMeasure(new Size(400, 300), SpacePlan.FullRender(300, 250))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(300, 250));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw() => SimpleContainerTests.Draw<EnsureSpace>();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing.SpacePlan;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
@@ -9,12 +9,6 @@ namespace QuestPDF.UnitTests
|
||||
[TestFixture]
|
||||
public class ExtendTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure_ShouldHandleNullChild() => new Extend().MeasureWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Draw_ShouldHandleNullChild() => new Extend().DrawWithoutChild();
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenChildReturnsWrap()
|
||||
{
|
||||
@@ -24,8 +18,8 @@ namespace QuestPDF.UnitTests
|
||||
Child = x.CreateChild()
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new Wrap())
|
||||
.CheckMeasureResult(new Wrap());
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.Wrap())
|
||||
.CheckMeasureResult(SpacePlan.Wrap());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -39,8 +33,8 @@ namespace QuestPDF.UnitTests
|
||||
ExtendVertical = true
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new PartialRender(300, 100))
|
||||
.CheckMeasureResult(new PartialRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.PartialRender(300, 100))
|
||||
.CheckMeasureResult(SpacePlan.PartialRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -54,8 +48,8 @@ namespace QuestPDF.UnitTests
|
||||
ExtendVertical = true
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(300, 100))
|
||||
.CheckMeasureResult(new FullRender(400, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(300, 100))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -69,8 +63,8 @@ namespace QuestPDF.UnitTests
|
||||
ExtendVertical = false
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 100))
|
||||
.CheckMeasureResult(new FullRender(400, 100));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(400, 100));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -84,8 +78,11 @@ namespace QuestPDF.UnitTests
|
||||
ExtendVertical = true
|
||||
})
|
||||
.MeasureElement(new Size(400, 200))
|
||||
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 100))
|
||||
.CheckMeasureResult(new FullRender(100, 200));
|
||||
.ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 100))
|
||||
.CheckMeasureResult(SpacePlan.FullRender(100, 200));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw() => SimpleContainerTests.Draw<Extend>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
|
||||
namespace QuestPDF.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExternalLinkTests
|
||||
{
|
||||
[Test]
|
||||
public void Measure() => SimpleContainerTests.Measure<Hyperlink>();
|
||||
|
||||
// TODO: consider tests for the Draw method
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using SkiaSharp;
|
||||
using static SkiaSharp.SKFontStyleSlant;
|
||||
|
||||
namespace QuestPDF.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FontStyleSetTests
|
||||
{
|
||||
private void ExpectComparisonOrder(SKFontStyle target, SKFontStyle[] styles)
|
||||
{
|
||||
for (var i = 0; i < styles.Length - 1; i++)
|
||||
{
|
||||
var currentStyle = styles[i];
|
||||
var nextStyle = styles[i + 1];
|
||||
|
||||
FontStyleSet.IsBetterMatch(target, currentStyle, nextStyle).Should().BeTrue();
|
||||
FontStyleSet.IsBetterMatch(target, nextStyle, currentStyle).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_CondensedWidth()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 5, Upright),
|
||||
new SKFontStyle(500, 4, Upright),
|
||||
new SKFontStyle(500, 3, Upright),
|
||||
new SKFontStyle(500, 6, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_ExpandedWidth()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 6, Upright),
|
||||
new SKFontStyle(500, 7, Upright),
|
||||
new SKFontStyle(500, 8, Upright),
|
||||
new SKFontStyle(500, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 6, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_ItalicSlant()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 5, Italic),
|
||||
new SKFontStyle(500, 5, Oblique),
|
||||
new SKFontStyle(500, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 5, Italic), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_ObliqueSlant()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 5, Oblique),
|
||||
new SKFontStyle(500, 5, Italic),
|
||||
new SKFontStyle(500, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 5, Oblique), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_UprightSlant()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 5, Upright),
|
||||
new SKFontStyle(500, 5, Oblique),
|
||||
new SKFontStyle(500, 5, Italic)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_ThinWeight()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(300, 5, Upright),
|
||||
new SKFontStyle(200, 5, Upright),
|
||||
new SKFontStyle(100, 5, Upright),
|
||||
new SKFontStyle(400, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(300, 5, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_RegularWeight()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(500, 5, Upright),
|
||||
new SKFontStyle(300, 5, Upright),
|
||||
new SKFontStyle(100, 5, Upright),
|
||||
new SKFontStyle(600, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(400, 5, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_IsBetterMatch_BoldWeight()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(600, 5, Upright),
|
||||
new SKFontStyle(700, 5, Upright),
|
||||
new SKFontStyle(800, 5, Upright),
|
||||
new SKFontStyle(500, 5, Upright)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(600, 5, Upright), styles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FontStyleSet_RespectsPriority()
|
||||
{
|
||||
var styles = new[]
|
||||
{
|
||||
new SKFontStyle(600, 5, Italic),
|
||||
new SKFontStyle(600, 6, Upright),
|
||||
new SKFontStyle(500, 6, Italic)
|
||||
};
|
||||
|
||||
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
|
||||
}
|
||||
}
|
||||
}
|
||||
+127
-57
@@ -29,40 +29,40 @@ namespace QuestPDF.UnitTests
|
||||
{
|
||||
grid.AlignLeft();
|
||||
|
||||
grid.Element(6).Element(childA);
|
||||
grid.Element(4).Element(childB);
|
||||
grid.Element(4).Element(childC);
|
||||
grid.Element(2).Element(childD);
|
||||
grid.Element(8).Element(childE);
|
||||
grid.Item(6).Element(childA);
|
||||
grid.Item(4).Element(childB);
|
||||
grid.Item(4).Element(childC);
|
||||
grid.Item(2).Element(childD);
|
||||
grid.Item(8).Element(childE);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Container();
|
||||
|
||||
expected.Stack(stack =>
|
||||
expected.Column(column =>
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(6).Element(childA);
|
||||
row.RelativeColumn(4).Element(childB);
|
||||
row.RelativeColumn(2).Element(new Empty());
|
||||
row.RelativeItem(6).Element(childA);
|
||||
row.RelativeItem(4).Element(childB);
|
||||
row.RelativeItem(2);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(4).Element(childC);
|
||||
row.RelativeColumn(2).Element(childD);
|
||||
row.RelativeColumn(6).Element(new Empty());
|
||||
row.RelativeItem(4).Element(childC);
|
||||
row.RelativeItem(2).Element(childD);
|
||||
row.RelativeItem(6);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(8).Element(childE);
|
||||
row.RelativeColumn(4).Element(new Empty());
|
||||
row.RelativeItem(8).Element(childE);
|
||||
row.RelativeItem(4);
|
||||
});
|
||||
});
|
||||
|
||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
||||
TestPlan.CompareOperations(structure, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -83,43 +83,43 @@ namespace QuestPDF.UnitTests
|
||||
{
|
||||
grid.AlignCenter();
|
||||
|
||||
grid.Element(6).Element(childA);
|
||||
grid.Element(4).Element(childB);
|
||||
grid.Element(4).Element(childC);
|
||||
grid.Element(2).Element(childD);
|
||||
grid.Element(8).Element(childE);
|
||||
grid.Item(6).Element(childA);
|
||||
grid.Item(4).Element(childB);
|
||||
grid.Item(4).Element(childC);
|
||||
grid.Item(2).Element(childD);
|
||||
grid.Item(8).Element(childE);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Container();
|
||||
|
||||
expected.Stack(stack =>
|
||||
expected.Column(column =>
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(1).Element(new Empty());
|
||||
row.RelativeColumn(6).Element(childA);
|
||||
row.RelativeColumn(4).Element(childB);
|
||||
row.RelativeColumn(1).Element(new Empty());
|
||||
row.RelativeItem(1);
|
||||
row.RelativeItem(6).Element(childA);
|
||||
row.RelativeItem(4).Element(childB);
|
||||
row.RelativeItem(1);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(3).Element(new Empty());
|
||||
row.RelativeColumn(4).Element(childC);
|
||||
row.RelativeColumn(2).Element(childD);
|
||||
row.RelativeColumn(3).Element(new Empty());
|
||||
row.RelativeItem(3);
|
||||
row.RelativeItem(4).Element(childC);
|
||||
row.RelativeItem(2).Element(childD);
|
||||
row.RelativeItem(3);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(2).Element(new Empty());
|
||||
row.RelativeColumn(8).Element(childE);
|
||||
row.RelativeColumn(2).Element(new Empty());
|
||||
row.RelativeItem(2);
|
||||
row.RelativeItem(8).Element(childE);
|
||||
row.RelativeItem(2);
|
||||
});
|
||||
});
|
||||
|
||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
||||
TestPlan.CompareOperations(structure, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -140,40 +140,110 @@ namespace QuestPDF.UnitTests
|
||||
{
|
||||
grid.AlignRight();
|
||||
|
||||
grid.Element(6).Element(childA);
|
||||
grid.Element(4).Element(childB);
|
||||
grid.Element(4).Element(childC);
|
||||
grid.Element(2).Element(childD);
|
||||
grid.Element(8).Element(childE);
|
||||
grid.Item(6).Element(childA);
|
||||
grid.Item(4).Element(childB);
|
||||
grid.Item(4).Element(childC);
|
||||
grid.Item(2).Element(childD);
|
||||
grid.Item(8).Element(childE);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Container();
|
||||
|
||||
expected.Container().Stack(stack =>
|
||||
expected.Column(column =>
|
||||
{
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(2).Element(new Empty());
|
||||
row.RelativeColumn(6).Element(childA);
|
||||
row.RelativeColumn(4).Element(childB);
|
||||
row.RelativeItem(2);
|
||||
row.RelativeItem(6).Element(childA);
|
||||
row.RelativeItem(4).Element(childB);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(6).Element(new Empty());
|
||||
row.RelativeColumn(4).Element(childC);
|
||||
row.RelativeColumn(2).Element(childD);
|
||||
row.RelativeItem(6);
|
||||
row.RelativeItem(4).Element(childC);
|
||||
row.RelativeItem(2).Element(childD);
|
||||
});
|
||||
|
||||
stack.Item().Row(row =>
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.RelativeColumn(4).Element(new Empty());
|
||||
row.RelativeColumn(8).Element(childE);
|
||||
row.RelativeItem(4);
|
||||
row.RelativeItem(8).Element(childE);
|
||||
});
|
||||
});
|
||||
|
||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
||||
TestPlan.CompareOperations(structure, expected);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Spacing
|
||||
|
||||
[Test]
|
||||
public void Spacing()
|
||||
{
|
||||
// arrange
|
||||
var structure = new Container();
|
||||
|
||||
var childA = TestPlan.CreateUniqueElement();
|
||||
var childB = TestPlan.CreateUniqueElement();
|
||||
var childC = TestPlan.CreateUniqueElement();
|
||||
var childD = TestPlan.CreateUniqueElement();
|
||||
|
||||
// act
|
||||
structure
|
||||
.Grid(grid =>
|
||||
{
|
||||
grid.Columns(16);
|
||||
grid.AlignCenter();
|
||||
|
||||
grid.VerticalSpacing(20);
|
||||
grid.HorizontalSpacing(30);
|
||||
|
||||
grid.Item(5).Element(childA);
|
||||
grid.Item(5).Element(childB);
|
||||
grid.Item(10).Element(childC);
|
||||
grid.Item(12).Element(childD);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Container();
|
||||
|
||||
expected.Column(column =>
|
||||
{
|
||||
column.Spacing(20);
|
||||
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.Spacing(30);
|
||||
|
||||
row.RelativeItem(3);
|
||||
row.RelativeItem(5).Element(childA);
|
||||
row.RelativeItem(5).Element(childB);
|
||||
row.RelativeItem(3);
|
||||
});
|
||||
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.Spacing(30);
|
||||
|
||||
row.RelativeItem(3);
|
||||
row.RelativeItem(10).Element(childC);
|
||||
row.RelativeItem(3);
|
||||
});
|
||||
|
||||
column.Item().Row(row =>
|
||||
{
|
||||
row.Spacing(30);
|
||||
|
||||
row.RelativeItem(2);
|
||||
row.RelativeItem(12).Element(childD);
|
||||
row.RelativeItem(2);
|
||||
});
|
||||
});
|
||||
|
||||
TestPlan.CompareOperations(structure, expected);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.UnitTests.TestEngine;
|
||||
|
||||
namespace QuestPDF.UnitTests
|
||||
{
|
||||
public static class Helpers
|
||||
{
|
||||
public static Random Random = new Random();
|
||||
|
||||
public static Size RandomSize => new Size(Random.Next(200, 400), Random.Next(100, 200));
|
||||
|
||||
public static void ShouldEqual(this IEnumerable<OperationBase> commands, IEnumerable<OperationBase> expected)
|
||||
{
|
||||
commands.Should().HaveSameCount(expected);
|
||||
|
||||
commands
|
||||
.Zip(expected)
|
||||
.ToList()
|
||||
.ForEach(x =>
|
||||
{
|
||||
x.First.Should().BeOfType(x.Second.GetType());
|
||||
x.First.Should().BeEquivalentTo(x.Second, y => y.RespectingRuntimeTypes());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user