Compare commits

...

563 Commits

Author SHA1 Message Date
MarcinZiabek e53b586943 Implemented automated image scaling 2023-05-01 14:23:46 +02:00
Marcin Ziąbek 9637dff1dc Image scaling dpi (#540)
* DPI-based image scaling prototype (not ready for production)

* Added ImageDpi API

* Added support for image DPI scaling
2023-04-30 11:28:14 +02:00
MarcinZiabek 1c9bccbeb2 Feature: added support for shared/global images 2023-04-17 02:08:04 +02:00
MarcinZiabek 176566801b 2022.12.3 release 2023-04-17 00:10:46 +02:00
MarcinZiabek 22a696fab9 Fix(#470): the inlined element is shown only once in the header but should be repeated on each page 2023-04-17 00:01:32 +02:00
MarcinZiabek 9809faccb6 Improvement (#528): added validation for color arguments 2023-04-16 23:49:47 +02:00
MarcinZiabek 6ad465b9fa Fix(#499): inconsistent text height when using multiple lines 2023-04-16 11:42:38 +02:00
MarcinZiabek e6c7befac4 Revert "Building QuestPDF Previewer for dotnet 7"
This reverts commit b05f76f848.
2023-03-15 19:48:56 +01:00
MarcinZiabek be3e4b59ec Revert "Update dotnet-desktop.yml"
This reverts commit e751bfd2ff.
2023-03-15 19:48:56 +01:00
Marcin Ziąbek e751bfd2ff Update dotnet-desktop.yml 2023-03-15 10:53:44 +01:00
MarcinZiabek b05f76f848 Building QuestPDF Previewer for dotnet 7 2023-03-14 12:28:04 +01:00
MarcinZiabek b5d7dbb346 2022.12.2 release 2023-03-12 22:14:17 +01:00
Marcin Ziąbek 0ab73f4f2b Update README.md 2023-03-11 22:18:34 +01:00
MarcinZiabek 458b379208 Remove loop to calculate maximum (target) width, remove capturing lambda 2023-03-07 21:22:45 +01:00
Marcin Ziąbek c3c0d7631c Merge pull request #454 from thomasstevens89/main
Update DynamicOptimized Example to use non-deprecated methods
2023-03-07 21:03:04 +01:00
MarcinZiabek a3ea8bceb6 Text rendering optimization: cache codepoint for space 2023-03-06 22:29:06 +01:00
MarcinZiabek 455d187897 Code formatting improvement 2023-03-06 21:42:38 +01:00
Marcin Ziąbek 65e5d36ded Merge pull request #474 from AntonyCorbett/fix_render_bug_382
Fix #382
2023-03-06 21:38:23 +01:00
Marcin Ziąbek ad5e8ab27d Merge pull request #489 from AntonyCorbett/perf_linq_02
Small perf improvement in LINQ (2)
2023-03-06 20:15:53 +01:00
Marcin Ziąbek a17197addc Merge pull request #490 from AntonyCorbett/var_scope_change_01
reduce scope of variable (remove unneeded calc)
2023-03-06 20:12:27 +01:00
Marcin Ziąbek a1e7cbbeb3 Merge pull request #505 from avobelk/fix-fallback-not-found-glyph
fix glyph check in FontFallback.MatchFallbackOption
2023-03-06 20:10:23 +01:00
Marcin Ziąbek c00ac5e9c7 Merge pull request #493 from AntonyCorbett/var_scope_change_02
reduce variable scope
2023-03-06 11:08:53 +01:00
Marcin Ziąbek 0e0a8d5d69 Merge pull request #488 from AntonyCorbett/perf_linq_01
Small perf improvement in LINQ
2023-03-06 10:54:10 +01:00
Marcin Ziąbek bc341da6dd Merge pull request #476 from AntonyCorbett/small_dictionary_perf
prevent double lookup
2023-03-06 10:49:00 +01:00
Alexander V 6096771b51 fix glyph check in FontFallback.MatchFallbackOption 2023-02-23 23:09:30 +03:00
Antony Corbett 4f097d0fed reduce variable scope 2023-02-13 17:06:15 +00:00
Antony Corbett 24beea80c7 reduce scope of variable (remove unneeded calc) 2023-02-12 14:06:55 +00:00
Antony Corbett e1e5778ff0 Small perf improvement in LINQ 2023-02-12 14:01:41 +00:00
Antony Corbett 8679391609 Small perf improvement in LINQ 2023-02-12 13:59:31 +00:00
Marcin Ziąbek c1b60287ca Update README.md 2023-02-12 00:01:47 +01:00
Marcin Ziąbek 011e1b7ce9 Update README.md 2023-02-10 00:21:17 +01:00
Antony Corbett 5fd72cbb4b prevent double lookup 2023-02-03 15:10:57 +00:00
Antony Corbett 7284998657 Fix #382 2023-02-03 10:20:39 +00:00
Marcin Ziąbek 30bd7420e2 Merge pull request #467 from AntonyCorbett/fix_exception_ctor
Fix exception ctor call.
2023-01-29 22:22:13 +01:00
Marcin Ziąbek bd48688670 Merge pull request #466 from AntonyCorbett/fix_multiple_enum
Avoid multiple enumeration
2023-01-29 22:20:48 +01:00
Marcin Ziąbek 68e3efde59 Merge pull request #465 from AntonyCorbett/unit_test_user_agent_fix
Add user agent string
2023-01-29 22:18:05 +01:00
Marcin Ziąbek 805fd55d94 Minor code formatting 2023-01-29 22:17:22 +01:00
MarcinZiabek b3a3deb354 Added example showing how to detect span position in text block (hack) 2023-01-29 22:00:14 +01:00
MarcinZiabek 68e4a10e81 Deleted obsolete performance tests 2023-01-29 22:00:14 +01:00
Antony Corbett e15a21ab0e Fix exception ctor call. 2023-01-26 14:31:44 +00:00
Antony Corbett f851221718 avoid multiple enumeration 2023-01-26 14:29:40 +00:00
Antony Corbett 91c93e68b5 Add user agent string 2023-01-26 13:49:42 +00:00
Marcin Ziąbek 3dcc35be97 Update README.md 2023-01-23 21:21:49 +01:00
Marcin Ziąbek 3f32c6e2c5 Update README.md 2023-01-19 10:07:09 +01:00
Thomas Stevens f1f609ccc1 use content() not stack() 2023-01-14 12:17:41 -05:00
Thomas Stevens 5c07485cc1 Update DynamicOptimizedExample to use non-deprecated methods 2023-01-14 12:09:11 -05:00
Marcin Ziąbek 42684ec180 Update README.md 2023-01-14 00:54:40 +01:00
MarcinZiabek 08f9f706ce Adjusted package details 2023-01-13 22:53:25 +01:00
MarcinZiabek 1f199423b0 Package description: use images from trusted sources 2023-01-13 22:48:40 +01:00
Marcin Ziąbek d8e640fcf3 Update README.md 2023-01-13 22:30:22 +01:00
MarcinZiabek fb02d97a10 Improved package description 2023-01-13 22:28:19 +01:00
MarcinZiabek d5f8a884d6 Adjusted package description 2023-01-13 22:05:31 +01:00
Marcin Ziąbek 5de5be6429 Update dotnet-desktop.yml 2023-01-13 21:41:08 +01:00
MarcinZiabek 96d57b241e 2022.12.1 2023-01-13 21:26:41 +01:00
Marcin Ziąbek 920e61fc5e Update dotnet-desktop.yml 2023-01-11 23:15:17 +01:00
Marcin Ziąbek 1cc606261c Update dotnet-desktop.yml 2023-01-11 23:04:22 +01:00
Marcin Ziąbek 0a6c021fe9 Update README.md 2023-01-11 22:54:23 +01:00
Marcin Ziąbek b65ee32daf Update README.md 2023-01-11 22:54:01 +01:00
MarcinZiabek e496917d84 Updated readme 2023-01-11 22:27:51 +01:00
MarcinZiabek a5004b986c Exposed missing API for dynamic components 2023-01-11 22:24:59 +01:00
MarcinZiabek 84d7fcf41f Improved documentation for the DocumentLayoutExceptionThreshold setting by providing the unit information 2023-01-10 12:23:48 +01:00
MarcinZiabek 641cc6dee2 Fixed: loading fonts from embedded resource via the FontManager.RegisterFontFromEmbeddedResource method 2023-01-09 11:59:11 +01:00
Marcin Ziąbek 9dbed14559 Update README.md 2023-01-06 00:48:29 +01:00
Marcin Ziąbek 6323a8dba2 Update README.md 2023-01-06 00:47:30 +01:00
Marcin Ziąbek 356dbb020d Rename LICENSE to LICENSE.md 2023-01-06 00:46:52 +01:00
Marcin Ziąbek bad6be1a28 Rename readme.md to README.md 2023-01-06 00:46:23 +01:00
MarcinZiabek 27c7383437 Updated repository structure 2023-01-06 00:45:12 +01:00
Marcin Ziąbek ecac19ee46 Update readme.md 2023-01-06 00:14:06 +01:00
Marcin Ziąbek fd37070d3b Update readme.md 2023-01-05 23:31:04 +01:00
Marcin Ziąbek 3b433f3efb Update readme.md 2023-01-04 01:22:56 +01:00
Marcin Ziąbek b3d6a39a98 Update readme.md 2023-01-04 00:34:13 +01:00
Marcin Ziąbek 8d1a449e69 Content cleanup 2023-01-03 23:58:39 +01:00
Marcin Ziąbek 7f0be69ffc Updated stargazers section, fixed readability 2023-01-03 23:53:10 +01:00
Marcin Ziąbek 8553131b99 Readme content adjustments 2023-01-03 23:46:35 +01:00
Marcin Ziąbek 1bf9198a51 Adjusted button sizes 2023-01-03 23:32:58 +01:00
MarcinZiabek 563b782f6a Fixed text configuration for twitter share button 2022-12-26 10:45:34 +01:00
MarcinZiabek edf8db878a Updated share links 2022-12-24 00:34:09 +01:00
Marcin Ziąbek 5fd6488068 Updated github star count 2022-12-24 00:12:35 +01:00
MarcinZiabek d6a7c3703d Removed GitHub sponsors section 2022-12-23 22:32:11 +01:00
MarcinZiabek 5844d3bdba Column: improved layout stability 2022-12-23 00:11:33 +01:00
Marcin Ziąbek 011d44304a Update readme.md 2022-12-14 13:36:56 +01:00
MarcinZiabek a087be8afe Adjusted release notes 2022-12-14 12:33:19 +01:00
MarcinZiabek 483cbb6d46 Nuget packaging: added configuration for readme files 2022-12-13 13:17:53 +01:00
Marcin Ziąbek ec76cbd696 Update dotnet-desktop.yml 2022-12-13 12:26:19 +01:00
Marcin Ziąbek a83d8c43fe Update dotnet-desktop.yml 2022-12-13 12:14:04 +01:00
Marcin Ziąbek 5f25e37f7f Test build script 2022-12-13 12:03:37 +01:00
MarcinZiabek cafd27a60d Upgraded library version, added release notes 2022-12-13 00:08:40 +01:00
MarcinZiabek 5082bbbdf2 Changed letter-spacing to be relative to the font size 2022-12-10 17:34:07 +01:00
MarcinZiabek d2ba21821f Fixed: the Alignment element enforces size constraints in both direction, even if only one is provided 2022-12-09 01:02:47 +01:00
MarcinZiabek 9bef7d64d5 Letter spacing: minor comment improvements 2022-12-06 23:23:19 +01:00
Marcin Ziąbek ca4352addd Merge pull request #398 from Bebo-Maker/letter-spacing
Letter spacing
2022-12-06 23:10:21 +01:00
MarcinZiabek 2906315fa7 Improved obsolete message 2022-12-06 23:05:43 +01:00
Marcin Ziąbek 6f036388b9 Merge pull request #362 from rstm-sf/feature/Text_TextSpanDescriptor
Replace type parameter text for Text
2022-12-06 23:03:44 +01:00
MarcinZiabek 9cd4fd740e Updated nuget dependencies in test projects 2022-12-06 22:51:32 +01:00
MarcinZiabek c97acada76 Upgraded SkiaSharp to 2.88.3 + Avalonia upgrade 2022-12-06 22:49:42 +01:00
Bennet Bo Fenner 19ff9062ad apply letter spacing to each unicode cluster 2022-11-18 15:34:30 +01:00
Bennet Bo Fenner e4f8243c9b add more examples for letter spacing 2022-11-18 15:32:04 +01:00
MarcinZiabek 1060e4a44a Updated QuestPDF.Previewer version to 2022.11.1 2022-11-11 13:02:43 +01:00
MarcinZiabek 983edd5f76 Added example for Arabic support 2022-11-07 12:44:00 +01:00
Marcin Ziąbek 5315165cf5 Update readme.md 2022-11-07 12:31:41 +01:00
MarcinZiabek ee3d87010e Added example: forcing text direction 2022-11-07 12:22:38 +01:00
MarcinZiabek 3ac91c4971 Improved content-direction examples 2022-11-06 01:18:13 +01:00
MarcinZiabek 8e450934ab 2022.11.0 2022-11-06 00:26:33 +01:00
Marcin Ziąbek bf193eec23 Update readme.md 2022-11-05 19:57:35 +01:00
Marcin Ziąbek c9104540aa Merge pull request #349 from QuestPDF/content-direction
Right-to-left content support
2022-11-05 19:54:41 +01:00
Marcin Ziąbek af60d84abe Merge branch 'main' into content-direction 2022-11-05 19:54:20 +01:00
Bennet Bo Fenner 4345ce857f add example for letter spacing 2022-11-03 16:45:49 +01:00
Bennet Bo Fenner 823572bf25 implement letter spacing 2022-11-03 16:45:40 +01:00
Bennet Bo Fenner e6bd63b3ec handle letter spacing in TextStyleManager 2022-11-03 16:43:49 +01:00
Bennet Bo Fenner bbf3d71e7e add letter spacing to TextStyle 2022-11-03 16:43:29 +01:00
MarcinZiabek d56117647b 2022.11.0-alpha1 2022-11-01 21:51:45 +01:00
MarcinZiabek 117913693c Fixed build (missing file) 2022-11-01 21:49:58 +01:00
MarcinZiabek 2ba716a5ba Text: fixed alignment when in RTL mode, added support for default alignment 2022-11-01 21:49:46 +01:00
MarcinZiabek be2108f6fe Inlined: fixed alignment when in RTL mode 2022-11-01 21:49:26 +01:00
MarcinZiabek c08bb963a6 Improved tests for alignment for Text and Inlined elements 2022-11-01 21:49:07 +01:00
MarcinZiabek 8ed8897fd1 Improved: the Inlined element should display children aligned to right (by default) when in RTL mode 2022-11-01 21:32:37 +01:00
MarcinZiabek 2a0e91af68 Fixed: the Decoration element is not aligned to right when in RTL mode 2022-11-01 21:32:04 +01:00
MarcinZiabek f647b79a0a Fixed: the Column element incorrectly displays children when in RTL mode 2022-11-01 21:31:46 +01:00
MarcinZiabek b1286bb536 Improved LTR and RTL tests 2022-11-01 21:26:47 +01:00
MarcinZiabek 43d1a55df0 Fixed: positioning elements in RTL mode in the Column element 2022-11-01 12:55:32 +01:00
MarcinZiabek d1cd7b06db Fixed: Page.Size should use points instead of inches (API consistency) 2022-11-01 12:55:13 +01:00
MarcinZiabek 7bce01d6e6 Fixed: table rendering in the RTL mode 2022-10-29 00:40:36 +02:00
MarcinZiabek e3ff2960e1 Fixed: table initialization process 2022-10-29 00:39:07 +02:00
MarcinZiabek 5d9e6f327b Version adjustments 2022-10-28 23:36:15 +02:00
MarcinZiabek b895931eb9 2022.11.0-alpha0 2022-10-28 23:30:23 +02:00
MarcinZiabek 86a35b7cd3 Deprecated the Grid element 2022-10-28 23:25:10 +02:00
MarcinZiabek 65990ebf59 Added the WordWrappingStability test 2022-10-21 12:05:45 +02:00
MarcinZiabek c348106b3f Page fluent: added possibility to select content direction 2022-10-19 21:45:16 +02:00
MarcinZiabek 9d86e9efd3 DynamicImage: simplified implementation 2022-10-19 20:08:41 +02:00
MarcinZiabek 9770575f9a Column: added content direction support 2022-10-19 20:04:31 +02:00
MarcinZiabek e6e6febf8b Inlined: added content direction support 2022-10-19 20:04:24 +02:00
Marcin Ziąbek 5cbacc7ea1 Update readme.md 2022-10-19 19:15:25 +02:00
MarcinZiabek 8214a8429d 2022.9.1 2022-10-15 23:03:25 +02:00
MarcinZiabek 389b8ce304 Inlined: improved behaviour predictability 2022-10-15 22:49:50 +02:00
MarcinZiabek e1f7cff4aa Fix: performance regression of the Table element #320 2022-10-11 23:19:13 +02:00
MarcinZiabek 6801425082 Fix: cells with RowSpan are not always displayed properly #320 2022-10-11 22:39:31 +02:00
MarcinZiabek ec31c9b063 Fix: CheckIfAllTextGlyphsAreAvailable and Fallback break hyperlinks 2022-10-11 10:31:31 +02:00
Rustam Sayfutdinov 8a57dceb9d Replace type parameter text for Text 2022-10-08 09:07:03 +03:00
MarcinZiabek 6c8867e1b3 Added test: ReusingTheSameImageFileShouldBePossible 2022-10-06 23:20:17 +02:00
Marcin Ziąbek 20d86cbfde Update readme.md 2022-10-05 22:49:03 +02:00
MarcinZiabek 16a164e5b8 Example: achieve proportional height division 2022-10-05 01:15:36 +02:00
Marcin Ziąbek 261f087b46 Update readme.md 2022-10-04 12:30:36 +02:00
Marcin Ziąbek c876350b05 Merge pull request #354 from CollinAlpert/fix_broken_links
Fix links in README
2022-10-03 22:10:19 +02:00
Collin Alpert 58f3932241 Update readme.md 2022-10-03 15:28:48 +02:00
MarcinZiabek 350abc2838 Improved RTL, fixed line breaking algorithm 2022-10-02 19:50:50 +02:00
MarcinZiabek 5d4c9a5dd2 Added example for RTL text 2022-10-01 00:18:31 +02:00
MarcinZiabek b31d097b61 Added possibility to force text direction 2022-09-30 20:45:28 +02:00
MarcinZiabek 9f6c091706 RTL: text 2022-09-30 20:33:36 +02:00
MarcinZiabek af2229eabe Fixed unit tests 2022-09-29 23:27:45 +02:00
MarcinZiabek b86946b396 Removed the Initialize method 2022-09-29 22:50:08 +02:00
MarcinZiabek e1ae97d3ca RTL: grid (example) 2022-09-29 21:31:21 +02:00
MarcinZiabek a7ac747776 RTL: dynamic 2022-09-29 21:28:22 +02:00
MarcinZiabek fab0f5bfe1 RTL: constrained 2022-09-29 21:21:25 +02:00
MarcinZiabek f5f90bd235 RTL: aspect ratio (fix) 2022-09-29 21:21:17 +02:00
MarcinZiabek 603dc13d0f RTL: aspect ratio 2022-09-29 21:12:46 +02:00
MarcinZiabek e277c6a8dc RTL: table, decoration, minimal box 2022-09-29 14:46:56 +02:00
MarcinZiabek 5ff9d03f20 Prototype for the RTL mode 2022-09-29 14:14:00 +02:00
MarcinZiabek 9ce9ca85be Added GenerationBenchmark to test async performance 2022-09-22 22:37:15 +02:00
MarcinZiabek 553c8ab719 2022.9.1 2022-09-19 12:05:44 +02:00
Marcin Ziąbek e768e9b06d Update readme.md 2022-09-19 00:58:55 +02:00
Marcin Ziąbek fd913a777c Update readme.md 2022-09-19 00:57:32 +02:00
MarcinZiabek ed9e6daec5 2022.9.0 2022-09-19 00:45:14 +02:00
Marcin Ziąbek ee6249a658 Merge pull request #341 from QuestPDF/2022.9
2022.9 Release
2022-09-19 00:43:29 +02:00
MarcinZiabek b307304f46 Fixed typo 2022-09-18 20:15:41 +02:00
MarcinZiabek f028f82e11 Removed unsued file 2022-09-17 20:42:14 +02:00
MarcinZiabek 719a3385f6 Updated Previewer to 2022.9 2022-09-16 19:52:10 +02:00
MarcinZiabek 2adff11400 2022.9.0-alpha1 2022-09-16 19:46:32 +02:00
MarcinZiabek 34fed6d547 Settings.CheckIfAllTextGlyphsAreAvailable improvements 2022-09-16 16:08:02 +02:00
MarcinZiabek db2df75624 Text example: fixed visuals 2022-09-15 22:19:28 +02:00
MarcinZiabek 6b535752df Fixed formatting page numbers 2022-09-15 22:12:06 +02:00
MarcinZiabek 556f87ff25 Settings renaming 2022-09-15 21:20:25 +02:00
MarcinZiabek fbebbd85eb Fixed build, adapted fallback process for cached TextStyle 2022-09-15 15:09:30 +02:00
MarcinZiabek 4650c2a4ea Merge branch 'font-fallback' into 2022.9
# Conflicts:
#	QuestPDF/Elements/Text/Items/TextBlockSpan.cs
#	QuestPDF/Fluent/TextStyleExtensions.cs
#	QuestPDF/Infrastructure/TextStyle.cs
2022-09-14 23:28:50 +02:00
MarcinZiabek 5390fc3f1b Implemented font-fallback as required configuration 2022-09-10 23:27:27 +02:00
MarcinZiabek 1ba01a1cf5 Fixed override value 2022-09-09 11:32:05 +02:00
MarcinZiabek d4448437ac Reduced creation of DefaultTextStyle objects 2022-09-08 17:29:52 +02:00
MarcinZiabek bc853f48fc Implemented TextStyleManager to reduce memory usage 2022-09-08 16:49:28 +02:00
MarcinZiabek 0468dd5f02 Font-fallback implementation 2022-09-08 13:23:59 +02:00
MarcinZiabek 3ba09ea826 Optimization: do not apply column element when text contains only one paragraph 2022-09-07 13:41:46 +02:00
MarcinZiabek 92abd32aae Updated dependencies 2022-09-07 13:03:30 +02:00
MarcinZiabek e17867d1f3 Added checking if all text glyphs are available in specified font 2022-09-07 00:54:39 +02:00
Marcin Ziąbek bd71f30c78 Merge pull request #326 from Bebo-Maker/fix-documentation-link-in-previewer
Fix documentation link for previewer
2022-09-06 16:09:38 +02:00
MarcinZiabek 6a78a4ebdb Moved document rendering flags to QuestPDF.Settings class 2022-09-06 13:45:48 +02:00
Bennet Bo Fenner 9fc721d66b Fix documentation link for previewer 2022-08-22 13:23:44 +02:00
MarcinZiabek 7d62dead86 2022.8.2 Version type 2022-08-21 20:14:16 +02:00
MarcinZiabek 52ad0f5c24 2202.8.2 2022-08-20 18:22:06 +02:00
Marcin Ziąbek 53107073a6 Merge pull request #322 from emanueleguastella/main
Fix DocumentLayoutException when creating a document with more than one page
2022-08-20 18:14:08 +02:00
Emanuele Guastella c71bb3ea59 Fix DocumentLayoutException when creating a document with more than one page 2022-08-20 14:17:52 +02:00
Marcin Ziąbek 6cced3c143 Update readme.md 2022-08-19 14:45:26 +02:00
MarcinZiabek 425ea59cfe 2022.8.1 2022-08-19 14:40:49 +02:00
MarcinZiabek 4d326496c6 Optimization for the Column element: do not measure child when available height is negative 2022-08-17 15:14:38 +02:00
MarcinZiabek b7b6488d16 Updated stability of rendering elements when negative space 2022-08-17 15:13:06 +02:00
MarcinZiabek f0ba5fc32d Fixed: page breaking rendering does not work in very specific corner cases 2022-08-16 23:59:05 +02:00
MarcinZiabek 04da32e0e7 Stability improvements for text wrapping 2022-08-16 16:33:37 +02:00
MarcinZiabek 5bdb338996 Fixed: default text style does not always work 2022-08-16 16:25:39 +02:00
MarcinZiabek 06b30f2ad6 2022.8.0 2022-08-15 12:58:09 +02:00
MarcinZiabek d39f68a974 Fixed memory leak, issue #306 2022-08-13 20:06:23 +02:00
MarcinZiabek db9d8b5fcf Updated logo 2022-08-11 12:55:42 +02:00
Marcin Ziąbek a31a588b24 Update readme.md 2022-08-01 23:58:48 +02:00
MarcinZiabek cb2a3c6363 Previewer: added support for linux / macos 2022-07-31 23:24:45 +02:00
MarcinZiabek e775f62fab 2022.8 2022-07-31 23:05:18 +02:00
MarcinZiabek 056e3f244c Minor code adjustments 2022-07-30 21:30:11 +02:00
Marcin Ziąbek cd3f7f5a25 Merge pull request #222 from maartenba/mb-perf-5
Micro-optimization by compiling regular expression into QuestPDF assembly
2022-07-30 18:40:26 +02:00
Marcin Ziąbek a5805f6e43 Merge pull request #220 from maartenba/mb-perf-3
Re-use static variable instead of method call in TextStyle
2022-07-30 18:19:47 +02:00
Marcin Ziąbek abe7b2f14c Merge pull request #219 from maartenba/mb-perf-2
Reduce creation of new arrays in Queue<T>
2022-07-30 18:17:43 +02:00
Marcin Ziąbek 3e485a572c Merge pull request #218 from maartenba/mb-perf-1
Convert LINQ to foreach in Helpers.VisitChildren - Reduce GC pressure
2022-07-30 18:12:45 +02:00
MarcinZiabek fd0bb5b089 Fixed inlined bug with measuring elements 2022-07-30 16:30:37 +02:00
MarcinZiabek cc51b62b73 Added information about available font families 2022-07-29 23:53:55 +02:00
MarcinZiabek 8e16b5ad4f Fixed documentation links 2022-07-27 12:21:05 +02:00
MarcinZiabek 71e2743409 Changed default library font from Calibry to Lato. This font is also included with the library 2022-07-19 15:58:35 +02:00
MarcinZiabek ba9d3aa04b 2022.6.3 Fixed text rendering corner cases 2022-07-18 13:23:37 +02:00
MarcinZiabek 2a0b133185 Fixed incorrect file name 2022-06-23 20:32:36 +02:00
Marcin Ziąbek 6058dac524 Merge pull request #249 from wieslawsoltes/CreateGlobalJson
Add global.json
2022-06-23 00:41:36 +02:00
Marcin Ziąbek 25b8f62245 Merge pull request #248 from wieslawsoltes/SetApplicationName
Set application name
2022-06-23 00:40:51 +02:00
MarcinZiabek 2c31f3d5b5 2022.6.2 2022-06-23 00:16:13 +02:00
Wiesław Šoltés f7cd89ccf6 Add global.json 2022-06-15 21:55:44 +02:00
Wiesław Šoltés 6914a9063a Set application name 2022-06-15 21:53:34 +02:00
MarcinZiabek b87e8d5d4e Improved exception messages 2022-06-14 17:53:16 +02:00
MarcinZiabek d740d67a64 2022.6.1 2022-06-13 00:17:32 +02:00
MarcinZiabek a14e9ca61f 2022.6 2022-06-12 23:48:38 +02:00
MarcinZiabek 44b3ff8d0d Merge branch 'text-shaping-new' 2022-06-08 02:46:54 +02:00
Marcin Ziąbek df6b88e14a Update readme.md 2022-06-08 02:10:52 +02:00
MarcinZiabek d4103797aa Improved exception message when SkiaSharp throws the TypeInitializationException 2022-06-08 02:01:58 +02:00
MarcinZiabek d894914e7e Improved Previewer stability 2022-06-08 00:09:59 +02:00
MarcinZiabek 90d1ce7af7 2022.6.0-prerelease 2022-05-31 00:52:49 +02:00
MarcinZiabek 5fa32a06cc Text: fixed corner case 2022-05-26 00:42:50 +02:00
MarcinZiabek acdf1ed1aa Stability improvement 2022-05-25 00:21:50 +02:00
MarcinZiabek a0b32e5ecf Fixed Row.AutoItem width calculation 2022-05-25 00:21:50 +02:00
MarcinZiabek 539dc83303 Fixed Row.AutoItem width calculation 2022-05-24 23:50:53 +02:00
MarcinZiabek d97fa2cef1 Minor optimization of SkFont creation 2022-05-23 01:18:21 +02:00
MarcinZiabek 6d122c784d Implemented working text shaping 2022-05-22 20:25:11 +02:00
MarcinZiabek 28743a81d1 Fixed typo 2022-05-21 14:35:13 +02:00
Maarten Balliauw 1047854f77 Micro-optimization by compiling regular expression into QuestPDF assembly so there's no JIT compilation when using it 2022-05-19 13:04:08 +02:00
Maarten Balliauw c5fbf7263c Re-use static variable instead of method call in TextStyle 2022-05-19 13:03:43 +02:00
Maarten Balliauw fae2205ff8 Reduce creation of new arrays in Queue<T> 2022-05-19 13:03:14 +02:00
Maarten Balliauw 1cbe4b1dc8 Convert LINQ to foreach in Helpers.VisitChildren - Reduce GC pressure 2022-05-19 13:02:20 +02:00
MarcinZiabek 32b94cea43 Updated sponsorship 2022-05-12 00:40:29 +02:00
Marcin Ziąbek 0ca55a91e0 Update readme.md 2022-05-10 21:48:39 +02:00
MarcinZiabek 09e6b5253f Fixed class names 2022-05-10 12:43:13 +02:00
MarcinZiabek bacb136a3f Benchmark: grid element 2022-05-10 12:42:49 +02:00
MarcinZiabek b7bc640e31 Added new example to dynamic component: footer with alternating position 2022-05-09 18:18:06 +02:00
MarcinZiabek 6e6f884a5f Updated sponsorship section 2022-05-09 16:33:12 +02:00
MarcinZiabek b47a8ac409 Added more examples 2022-05-09 16:32:59 +02:00
MarcinZiabek e51082400c Dynamic Component: added more examples 2022-05-09 14:07:50 +02:00
MarcinZiabek 52cfa3ab7e Added note regarding JetBrains OSS Power Ups 2022-05-07 22:18:14 +02:00
MarcinZiabek cd181b1e2e Merge branch '2022.5' 2022-05-07 21:40:10 +02:00
Marcin Ziąbek e71601ad0c Merge pull request #208 from danielchalmers/patch-1
replace obsolete method in readme example
2022-05-07 18:46:09 +02:00
Daniel Chalmers 3041aa53cc replace obsolete method in readme example
Warning	CS0618	'PageDescriptor.Background(string)' is obsolete: 'This element has been renamed since version 2022.3. Please use the PageColor method.'
2022-05-06 19:37:17 -05:00
MarcinZiabek 0ebf2833af Updated release notes 2022-05-06 21:17:16 +02:00
MarcinZiabek 25e6d9fbca Adjusted library versions 2022-05-06 21:09:16 +02:00
Marcin Ziąbek f80149792d Merge pull request #178 from jnyrup/Dispose
Explicit disposal of disposables
2022-05-06 20:59:35 +02:00
Marcin Ziąbek 2beee1d22e Update PreviewerService.cs 2022-05-06 20:59:06 +02:00
MarcinZiabek 1af7c0a144 Adjusted code related to subscript/superscript 2022-05-06 20:55:18 +02:00
Marcin Ziąbek eeca67e5bc Merge pull request #179 from Bebo-Maker/main
Implement subscript/superscript text
2022-05-06 00:09:31 +02:00
MarcinZiabek 4da3ef5dfa Fixed breaking long words 2022-05-05 23:52:17 +02:00
MarcinZiabek f3d4151273 Improved performance of the table rendering algorithm (square to linear complexity) 2022-05-05 23:20:23 +02:00
Marcin Ziąbek 9a7e397db2 Merge pull request #197 from knoxyz/patch-2
Replaced the obsolete methods from 2022.3 (FontType, Color and Size)
2022-05-05 18:23:11 +02:00
Marcin Ziąbek d81f21e658 Merge pull request #196 from knoxyz/patch-1
Update <TargetFramework> from 3.1 to net6.0
2022-05-05 18:11:21 +02:00
Marcin Ziąbek 78909c6edf Merge pull request #199 from knoxyz/patch-4
Replaced the obsolete methods from 2022.3 (InternalLink and Color)
2022-05-05 17:48:28 +02:00
Marcin Ziąbek a2d81b6adf Merge pull request #200 from knoxyz/patch-3
Replaced the obsolete methods from 2022.3 (ExternalLink and Location)
2022-05-05 17:47:40 +02:00
Marcin Ziąbek 4a761c023f Merge pull request #201 from simusr2/main
Replaced PageEnd with PageStart in PageNumberWithinSection
2022-05-05 17:46:30 +02:00
Simone Anile 24bbd06dff Replaced PageEnd with PageStart in PageNumberWithinSection 2022-04-29 15:19:58 +02:00
knoxyz 44bd646bab Replaced the obsolete methods from 2022.3 (InternalLink and Color) 2022-04-29 11:36:28 +02:00
knoxyz 5f0291b2c4 Replaced the obsolete methods from 2022.3 (ExternalLink and Location) 2022-04-29 11:32:20 +02:00
knoxyz 1b91015d8f Replaced the obsolete methods from 2022.3 (FontType, Color and Size) 2022-04-28 16:21:56 +02:00
knoxyz 2b6444463d Update <TargetFramework> from 3.1 to net6.0 2022-04-28 16:13:44 +02:00
MarcinZiabek a2629575e8 Dynamic: simplified container composition process 2022-04-27 09:50:17 +02:00
MarcinZiabek c8824021cc Dynamic: generalized dynamic element size measurement 2022-04-27 09:24:44 +02:00
MarcinZiabek e1101d870d Dynamic: improve state management 2022-04-27 06:56:13 +02:00
MarcinZiabek 152304b467 Dynamic: improved TextStyle handling 2022-04-26 01:11:40 +02:00
MarcinZiabek 8a1be90c4f Ported dynamic component implementation prototype 2022-04-26 00:36:50 +02:00
MarcinZiabek bc8a9e5dc5 Fixed mutating text style for page-related text items 2022-04-23 23:13:38 +02:00
Marcin Ziąbek e54e09de15 Merge pull request #185 from mikasius/main
Renamed logo.png
2022-04-23 23:03:37 +02:00
Sergey Metlenkin c49a424f87 Renamed logo.png
Otherwise solution won't build
2022-04-22 10:59:12 +07:00
Bebo-Maker c63b0658f3 Ignore FontPosition when calculating font metrics. 2022-04-12 19:14:00 +02:00
Bebo-Maker 82cd1d7835 Add example for superscript/subscript. 2022-04-12 18:49:34 +02:00
Bebo-Maker 3ffab6e933 Implement superscript and subscript. 2022-04-12 18:48:28 +02:00
Marcin Ziąbek e4d55e0298 Merge pull request #177 from jnyrup/ArgumentException
Use `paramName` overload of `ArgumentException`
2022-04-11 22:03:40 +02:00
Jonas Nyrup a6f4fd7f49 explicit disposal 2022-04-11 21:36:50 +02:00
Jonas Nyrup 048a4748b2 Use paramName overload of ArgumentException 2022-04-11 21:33:33 +02:00
Marcin Ziąbek 8cc2fb8696 Merge pull request #169 from fredericoregateiro/AvaloniaCompiledBindings
Enable compiled bindings on Previewer
2022-04-08 22:17:41 +02:00
MarcinZiabek 8e7b528cd9 Updated install command in readme 2022-04-08 22:15:12 +02:00
MarcinZiabek 26193313b8 Previewer: hide "Show in default browser" button when no document available 2022-04-08 22:14:19 +02:00
MarcinZiabek 555825e8be Previewer: throwing exception when cannot connect with frontend 2022-04-08 22:14:19 +02:00
Frederico Regateiro ddde8e7517 enable compiled bindings on PreviewerWindow 2022-04-06 14:08:53 +01:00
Marcin Ziąbek d2c82b5988 Update readme.md 2022-04-05 14:54:33 +02:00
Marcin Ziąbek d82aae95b5 Update readme.md 2022-04-05 14:34:00 +02:00
Marcin Ziąbek 5c11a2ab6a Update readme.md 2022-04-05 14:30:51 +02:00
MarcinZiabek 03e3a80fd9 Fixed logo resource for QuestPDF.Previwer 2022-04-04 23:26:16 +02:00
MarcinZiabek 4692c5ce62 Fixed QuestPDF.Previewer build 2022-04-04 23:24:02 +02:00
MarcinZiabek 919f916219 2022.4 release 2022-04-04 23:20:22 +02:00
MarcinZiabek 7a32f774a1 Fixed spelling 2022-04-04 00:38:58 +02:00
MarcinZiabek fba71e6392 Previewer: stop debugging session when previewer is closed 2022-04-04 00:19:36 +02:00
MarcinZiabek e27585a504 Fixed previewer: first document refresh sometimes does not work 2022-04-02 00:23:58 +02:00
MarcinZiabek 9be497ee41 Fixed automatically starting previewer application on custom port 2022-04-01 19:26:54 +02:00
MarcinZiabek 0fc0db55d2 Better button style path in previewer 2022-03-31 23:14:00 +02:00
MarcinZiabek 9e7a1ed49d Previewer improvements 2022-03-31 23:11:34 +02:00
MarcinZiabek c137bcfcde Improved look and feel 2022-03-31 18:33:34 +02:00
MarcinZiabek b80b3414d8 Added http-based previewer 2022-03-31 15:44:28 +02:00
MarcinZiabek 5f7cee3420 Removed old previewer implementation 2022-03-30 23:38:51 +02:00
MarcinZiabek 435c42ab9e Changed previewer communication layer to http 2022-03-30 23:37:37 +02:00
MarcinZiabek 7b4923b45d Merge remote-tracking branch 'origin/previewer' 2022-03-27 20:15:02 +02:00
MarcinZiabek 8732b7e50b Renaming 2022-03-27 20:12:22 +02:00
MarcinZiabek 6b31322f92 Fixed preview button labels 2022-03-27 17:29:50 +02:00
MarcinZiabek 6155d21207 Previewer: added buttons for documentation and project sponsoring 2022-03-27 14:49:50 +02:00
Marcin Ziąbek a0909eb057 Create FUNDING.yml 2022-03-26 21:06:44 +01:00
MarcinZiabek 11ff53946d Introduced new line breaking algorithm: break anywhere 2022-03-26 03:34:31 +01:00
MarcinZiabek 0711bca1e1 Improved respecting spaces at the beginning and end of text block, fixed breaking long words that do not fit in line 2022-03-26 02:58:55 +01:00
MarcinZiabek 297ca48c70 Code cleanup 2022-03-24 23:09:09 +01:00
Marcin Ziąbek d2601e9e5a Merge pull request #157 from Bebo-Maker/previewer
Previewer - ViewModel for PreviewerWindow
2022-03-24 22:20:28 +01:00
Bebo-Maker 421a926780 Fix vertical scroll bar visibility. 2022-03-24 22:05:49 +01:00
Bebo-Maker 307759d1b3 Remove StyledProperties and rework bindings. 2022-03-24 22:01:10 +01:00
Bebo-Maker 00bcb2c25b Add ViewModel for PreviewerWindow. 2022-03-24 21:59:55 +01:00
MarcinZiabek e430484e85 Fixed zooming out 2022-03-24 13:54:38 +01:00
MarcinZiabek d24d887a3a Previewer: simplified translate operations 2022-03-24 13:35:02 +01:00
MarcinZiabek 404914ea7e Previewer: added button to show generated PDF 2022-03-24 01:02:57 +01:00
Marcin Ziąbek 545b76fd40 Merge pull request #155 from Bebo-Maker/previewer
Previewer - Fix multiple small issues
2022-03-24 00:04:34 +01:00
Marcin Ziąbek c801894ec4 Merge branch 'previewer' into previewer 2022-03-24 00:04:28 +01:00
MarcinZiabek c21744e7de Fixed scrolling math 2022-03-23 23:31:27 +01:00
Bebo-Maker 734d116bfe Fix scroll viewer visibility. 2022-03-23 12:58:58 +01:00
Bebo-Maker 0abb67b748 Unregister HotReload handler when window is closed 2022-03-23 09:22:46 +01:00
Bebo-Maker 828bb86737 Fix MaxWidth calculation when pages are empty. 2022-03-23 08:35:53 +01:00
Bebo-Maker 040c47e017 Fix issue when showing previewer multiple times.
Previously when calling ShowPreviewer  in the same process multiple times lead to an Exception inside Avalonia.
2022-03-23 08:35:28 +01:00
MarcinZiabek ff95fe287a Added scrollbar interactions 2022-03-23 01:10:15 +01:00
MarcinZiabek 47e9a49fe5 Fixed scroll, more code refactoring 2022-03-21 01:33:33 +01:00
MarcinZiabek b2826a06b8 Code refactorization + cleanup 2022-03-21 01:16:26 +01:00
MarcinZiabek 321cba32ce Implemented basic canvas interactions 2022-03-21 01:02:53 +01:00
MarcinZiabek 26fdbb714d Simplified rendering operation 2022-03-20 01:53:51 +01:00
Marcin Ziąbek f0cec8988a Merge pull request #147 from Bebo-Maker/document-previewer
Document previewer
2022-03-20 00:48:50 +01:00
Bebo-Maker ea2102fe4c WIP Implemented virtualization of pages.
Render pages into seperate SKPictures
2022-03-19 17:26:58 +01:00
Bebo-Maker 6cca3ed057 Refactor custom drawing operation. 2022-03-17 22:32:37 +01:00
Bebo-Maker 9afe4ec104 Add button for generating pdf in previewer. 2022-03-17 20:03:20 +01:00
Bebo-Maker 846679007f Enable dark mode for previewer and cleanup UI. 2022-03-17 19:35:46 +01:00
Bebo-Maker 0946607154 Add table to example. 2022-03-17 12:05:27 +01:00
Bebo-Maker d5f86e0d70 Fixed rendering issue where content was clipped. 2022-03-17 11:44:40 +01:00
Bebo-Maker 346513ee85 Optimize document rendering.
We dont need to render the document two times anymore.
2022-03-17 10:34:00 +01:00
Bebo-Maker d18ee5f282 Allow intersection after first RenderPass. 2022-03-17 10:32:41 +01:00
Bebo-Maker a85bc0abc1 Add example for using document previewer. 2022-03-16 22:54:03 +01:00
Bebo-Maker 82e39df572 Enable SKPaint.IsAntialias in FontManager. 2022-03-16 22:48:30 +01:00
Bebo-Maker 1311b6db32 Add PreviewerApp and provide extensions for displaying previewer. 2022-03-16 22:48:07 +01:00
Bebo-Maker b5645bfbd5 Implement document preview. 2022-03-16 22:47:05 +01:00
Bebo-Maker 8217b3b54a Implement HotReloadManager. 2022-03-16 22:46:21 +01:00
Bebo-Maker 726759f47a Add size tracking canvas. 2022-03-16 22:45:57 +01:00
Bebo-Maker bbd9c3379e Change access modifier of RenderDocument to internal. 2022-03-16 22:45:39 +01:00
Bebo-Maker 697c5e238d Add InternalsVisibleTo for QuestPDF.Previewer in QuestPDF AssemblyInfo. 2022-03-16 22:45:13 +01:00
Bebo-Maker 21a92be87e Add .editorconfig . 2022-03-16 22:44:45 +01:00
Bebo-Maker b0cca1ff48 Add QuestPDF.Previewer and QuestPDF.Previewer.Examples 2022-03-16 22:42:16 +01:00
Marcin Ziąbek 78c5049eda Update readme.md 2022-03-15 23:23:18 +01:00
MarcinZiabek 3d0ca07b43 Release 2022.3.1 2022-03-15 13:06:09 +01:00
MarcinZiabek a67fa754af Fixed NullReferenceException when the text is null 2022-03-15 11:55:59 +01:00
MarcinZiabek 208235ad1e Updated description 2022-03-14 13:59:26 +01:00
Marcin Ziąbek f24416474a Update readme.md 2022-03-14 13:49:21 +01:00
MarcinZiabek 01c2e8d3f5 Updated documentation. Release 2022.03 2022-03-14 13:17:33 +01:00
MarcinZiabek b3cef238ec Improved page color API 2022-03-13 22:47:17 +01:00
Marcin Ziąbek aede62c135 Update readme.md 2022-03-12 23:04:11 +01:00
MarcinZiabek db9db95dcc Fixed build 2022-03-12 19:20:01 +01:00
MarcinZiabek 92263685d7 Merge branch '2022.03'
# Conflicts:
#	QuestPDF.Examples/TextExamples.cs
#	QuestPDF/QuestPDF.csproj
2022-03-12 19:17:38 +01:00
MarcinZiabek ba4be521aa 2022.2.7 2022-03-12 19:01:39 +01:00
Marcin Ziąbek f6967dfe8b Update readme.md 2022-03-12 16:42:26 +01:00
MarcinZiabek ff3dfe7831 Fixed logo size 2022-03-12 16:39:33 +01:00
MarcinZiabek 5a1990d857 Added more shields 2022-03-12 16:38:03 +01:00
MarcinZiabek 1b9b164583 DefaultTextStyle API improvements 2022-03-12 16:11:03 +01:00
Marcin Ziąbek 9c64a6bc8d Merge pull request #128 from loxsmoke/main
Add nuget badges to readme.md file
2022-03-12 16:06:04 +01:00
MarcinZiabek 5402e5fedc Fixed text rendering issues 2022-03-12 12:17:00 +01:00
MarcinZiabek 2c14f91ebe Added support for background and foreground in page API 2022-03-11 18:04:30 +01:00
MarcinZiabek b533a32b61 Text API naming adjustments 2022-03-11 13:23:36 +01:00
MarcinZiabek 262bd3c182 Improved backwards compatibility 2022-03-09 22:13:51 +01:00
MarcinZiabek fdf8e3eb1a Fixed text rendering corner case: measuring span with space at the end of the line may overflow available space 2022-03-08 18:33:34 +01:00
MarcinZiabek fcff989ab2 Improved text API 2022-03-08 17:27:30 +01:00
MarcinZiabek 054e7a5f20 Added minimal API example 2022-02-28 15:41:10 +01:00
MarcinZiabek a92cc25fb1 Improved font matching and exception message. Refactored tests. 2022-02-27 15:19:50 +01:00
MarcinZiabek 8db283d559 Code refactorization + added support for multi typeface font types 2022-02-25 23:02:42 +01:00
LoxSmoke 456c7a735b Update readme.md 2022-02-24 19:55:36 -08:00
LoxSmoke 5bf2a9a3d3 Nuget badges in readme file 2022-02-24 19:53:51 -08:00
Marcin Ziąbek 8a64abaac2 Merge pull request #106 from SvizelPritula/main
FontManager: Add support for multiple variants of font families registered at runtime
2022-02-21 22:26:51 +01:00
MarcinZiabek 68df390d0e Element renaming + custom text format 2022-02-21 00:57:53 +01:00
MarcinZiabek d73c694452 Added minimal API 2022-02-20 16:17:43 +01:00
MarcinZiabek 69e268733c 2022.2.5 2022-02-18 23:31:53 +01:00
MarcinZiabek 657bbe2aac 2022.2.4 2022-02-18 21:48:57 +01:00
MarcinZiabek 4479a49ad0 Improved support for page sections 2022-02-16 15:34:54 +01:00
MarcinZiabek 63288dfb60 Updated examples 2022-02-07 22:29:59 +01:00
MarcinZiabek fc325d8b76 2022.2.3 2022-02-07 22:25:48 +01:00
Marcin Ziąbek 5ffeaa3075 Merge pull request #119 from B-wareBS/features/unit-conversion-fix
Fixed an issue with unit conversion.
2022-02-07 22:04:55 +01:00
Chris de Jong-Pobedinskiy fe431fbc12 Fixed an issue with unit conversion.
Fixed an issue where unit conversions from mm to pt would be off by a
factor of 100.

This fixes #118
2022-02-07 13:56:20 +01:00
Marcin Ziąbek e0de408821 2022.2.2 Fixed regression: exception when Column/Row have no items 2022-02-01 23:39:43 +01:00
Marcin Ziąbek 8ce6afef5a Simplified readme 2022-02-01 11:14:38 +01:00
Marcin Ziąbek 1c70b20028 Added examples for execution order 2022-01-31 00:15:10 +01:00
Marcin Ziąbek 3aef4ec4c9 2022.2.1 2022-01-30 23:46:11 +01:00
Marcin Ziąbek 3649607bd9 Merge remote-tracking branch 'origin/2022.02'
# Conflicts:
#	QuestPDF.Examples/RowExamples.cs
#	QuestPDF.UnitTests/RowTests.cs
#	QuestPDF/Elements/Row.cs
#	QuestPDF/Fluent/RowExtensions.cs
#	QuestPDF/QuestPDF.csproj
#	QuestPDF/Resources/ReleaseNotes.txt
2022-01-30 23:44:20 +01:00
Marcin Ziąbek 9a6b11ab85 Updated examples and readme 2022-01-30 22:52:56 +01:00
Marcin Ziąbek ac29ed4794 2022.2.0-beta2 2022-01-26 22:26:47 +01:00
Marcin Ziąbek 5f7da8b5b3 Line: added default configuration 2022-01-26 22:26:34 +01:00
Benjamin Swart 78eef45ce2 FontManager: Add support for multiple variants of font families registered at runtime 2022-01-24 15:13:41 +01:00
Marcin Ziąbek 5424d9f0a0 2022.2.0-beta1 2022-01-24 14:53:01 +01:00
Marcin Ziąbek 946fe91a98 WriteOnlyStream refactorization 2022-01-24 00:34:27 +01:00
Marcin Ziąbek b5839d3989 Merge pull request #65 from schulz3000/main
fix rendering direct to aspnet core response stream
2022-01-24 00:17:14 +01:00
MarcinZiabek 2ca6d1cb47 Decoration: improved implementation, fixed unit tests 2022-01-23 23:08:18 +01:00
Marcin Ziąbek 49a3371af7 Added StopPaging element 2022-01-23 21:42:03 +01:00
Marcin Ziąbek 3f3ada6d8a Minor code adjustments 2022-01-23 21:41:45 +01:00
Marcin Ziąbek ba409a8712 Create codeql-analysis.yml 2022-01-21 03:11:22 +01:00
Marcin Ziąbek b96c67a8af Fixed Column tests 2022-01-21 00:09:39 +01:00
Marcin Ziąbek b9fbb9267f Obsolete methods refactorization 2022-01-18 23:24:10 +01:00
Marcin Ziąbek 272b0fc11a Added support for unit types 2022-01-18 23:14:57 +01:00
Marcin Ziąbek b2cc7bbd36 Renamed Decoration element 2022-01-16 17:08:57 +01:00
Marcin Ziąbek e3ce194fd1 Simple SVG example 2022-01-16 17:03:01 +01:00
Marcin Ziąbek 9b892c86ed 2022.1.0 2022-01-10 02:43:58 +01:00
Marcin Ziąbek c9833d410d 2022.1.0-beta6 2022-01-09 03:08:18 +01:00
Marcin Ziąbek f8057a840c Added: Line, Reimplemented: Column, Row and Decoration 2022-01-09 00:11:34 +01:00
Marcin Ziąbek a2ce31022c Improved default behavior of fluent configuration 2022-01-08 01:11:25 +01:00
Marcin Ziąbek 763fdfac0f Row: fixed paging behavior, Table: improved paging behavior for already rendered elements 2022-01-07 13:15:27 +01:00
Marcin Ziąbek ba8b35b1c0 Implemented ScaleToFit element 2022-01-07 00:09:25 +01:00
Marcin Ziąbek 648a359d15 Implemented the PreventPaging element 2022-01-06 22:19:33 +01:00
Marcin Ziąbek 630d3389d3 Table: added support for headers and footers 2022-01-06 21:36:27 +01:00
Marcin Ziąbek a7c3c88e81 Updated release notes 2022-01-06 19:57:22 +01:00
Marcin Ziąbek 9524cc6eb1 2022.1.0-beta3 Renaming Box() to MinimalBox() 2022-01-06 19:57:22 +01:00
Marcin Ziąbek 4152b67679 Table: row height fixes for overlapping cells. Added code examples 2022-01-06 19:57:22 +01:00
Marcin Ziąbek 8020cb30cb Table: improved repeating+paging support, added example 2022-01-06 19:57:22 +01:00
Marcin Ziąbek 9358fb8937 Fixed: traversing elements graph 2022-01-06 19:57:21 +01:00
Marcin Ziąbek eb297177ea VisitChildren -> GetChildren traversal refactorization 2022-01-06 19:57:21 +01:00
Marcin Ziąbek 7f651932b9 Table: added default style, fixed bugs, added examples 2022-01-06 19:57:21 +01:00
Marcin Ziąbek caaae5fa1c Table: fixed cross-cell size adjusting 2022-01-06 19:57:21 +01:00
Marcin Ziąbek f76caa28b1 Update Table.cs 2022-01-06 19:57:21 +01:00
MarcinZiabek ea92655ef5 Typo fixes 2022-01-06 19:57:21 +01:00
MarcinZiabek 3f8463e9b7 2022.1.0-beta0 2022-01-06 19:57:21 +01:00
MarcinZiabek 02e25b193d 2022.1.0-alpha0 2022-01-06 19:57:21 +01:00
MarcinZiabek 7cc272ff9e Border radius: added example 2022-01-06 19:57:21 +01:00
MarcinZiabek b8ea30be23 Improved readibility of the table layout algorithm 2022-01-06 19:57:21 +01:00
MarcinZiabek 06418238dc Table layout: refactorization 2022-01-06 19:57:21 +01:00
MarcinZiabek ed73c5b82d Table: layouting improvements for paging 2022-01-06 19:57:21 +01:00
MarcinZiabek 96732b5856 Fixed: corner cases of paging support 2022-01-06 19:57:21 +01:00
MarcinZiabek c7008ad940 Improved wrapping support 2022-01-06 19:57:21 +01:00
MarcinZiabek 940616cd3e Table: optimized rendering performance 2022-01-06 19:57:21 +01:00
MarcinZiabek 01a80032b0 Table: minor optimizations + performance test 2022-01-06 19:57:21 +01:00
MarcinZiabek 3e5e3843d2 Rendering algorithm partially working 2022-01-06 19:57:21 +01:00
MarcinZiabek d3911d5687 Table: refactorization, cell placement algorithm 2022-01-06 19:57:21 +01:00
Marcin Ziąbek 82e4dd36f0 Improved table paging support 2022-01-06 19:57:21 +01:00
Marcin Ziąbek 561d6a004c Row: added support for mixed columns (constant + relational), good when performing visual column merging 2022-01-06 19:57:20 +01:00
Marcin Ziąbek 59b77e55d4 Improved Row element stability 2022-01-06 19:57:20 +01:00
Marcin Ziąbek ea398c562f Merge pull request #64 from markhewett/us-page-sizes
Tweak US Letter and Legal page sizes
2022-01-04 19:31:57 +01:00
Xaver Schulz cb493562fc fix rendering direct to aspnet core response stream
adding a WrapperStream to support streams that not implement the Position property needed by SkiaSharp.
e.g. useful for the aspnet core response stream

fix #52
2021-12-10 21:07:42 +01:00
Marcin Ziąbek 5f636beb9d Added missing assertions to test that are supposed to throw an exception 2021-12-09 17:10:45 +01:00
Hewett, Mark A 5b85ae2627 Tweak US Letter and Legal page sizes
Adobe Acrobat Reader DC now shows the correct sizes for letter and legal size documents.
2021-12-08 19:17:42 -06:00
Marcin Ziąbek 10683776bb 2021.12.0 2021-12-06 09:28:02 +01:00
Marcin Ziąbek f2c47c4fd3 2021.12.0-alpha1 2021-11-30 00:34:04 +01:00
Marcin Ziąbek 77b8f04659 Synced to 2021.12-alpha0 2021-11-19 00:50:38 +01:00
Marcin Ziąbek 5235ada66f Merge branch 'main' into element-proxy
# Conflicts:
#	QuestPDF/Drawing/PdfCanvas.cs
#	QuestPDF/QuestPDF.csproj
2021-11-19 00:46:46 +01:00
Marcin Ziąbek 4ce66878f2 2021.12.0-alpha0 2021-11-19 00:24:32 +01:00
Marcin Ziąbek 79cc5f1507 Added support for XPS rendering 2021-11-19 00:22:45 +01:00
Marcin Ziąbek 7c7d461c4b Merge pull request #53 from donmurta/main
Add simple chart example
2021-11-14 23:09:27 +01:00
Marcin Ziąbek 63af713935 2021.11.4 - Fixed measuring the Inlined element 2021-11-14 23:03:22 +01:00
Don Murta 2419a25cbd Add simple chart example 2021-11-09 10:26:46 -07:00
Marcin Ziąbek 014ec15908 2021.11.3 2021-11-07 16:46:34 +01:00
Marcin Ziąbek 82e29d5fdd ImagePlaceholder.Solid = true; 2021-11-07 16:19:54 +01:00
Marcin Ziąbek c64754241d Updated base to 2021.11 2021-11-04 01:02:44 +01:00
Marcin Ziąbek 9de87061e4 Merge branch 'main' into element-proxy
# Conflicts:
#	QuestPDF.ReportSample/Layouts/PhotoTemplate.cs
#	QuestPDF.ReportSample/Layouts/SectionTemplate.cs
#	QuestPDF.ReportSample/Tests.cs
#	QuestPDF/Drawing/DocumentGenerator.cs
#	QuestPDF/Elements/Constrained.cs
#	QuestPDF/Infrastructure/Position.cs
#	QuestPDF/Infrastructure/Size.cs
2021-11-04 00:22:22 +01:00
Marcin Ziąbek 86cfd22316 2021.11.0-beta3 2021-11-03 21:39:20 +01:00
Marcin Ziąbek 520bfc840c Improved code benchmarking (removed an unnecessary cost of image placeholder generation) 2021-11-03 21:22:08 +01:00
Marcin Ziąbek 22cdad69b7 Text element improvement: null string behaves like an empty text, not throws an exception 2021-11-03 21:21:23 +01:00
Marcin Ziąbek d260fa7587 Added generating symbols 2021-10-29 01:30:28 +02:00
Marcin Ziąbek 011668fb4c Image: added support for common overloads 2021-10-29 01:24:56 +02:00
Marcin Ziąbek 5a886452cf Merge pull request #40 from QuestPDF/2021.11
2021.11
2021-10-23 03:07:56 +02:00
Marcin Ziąbek b044208195 Updated nuget details 2021-10-23 03:02:18 +02:00
Marcin Ziąbek dadb8a5087 Improved test engine. Added more examples 2021-10-23 02:59:47 +02:00
Marcin Ziąbek 11f0809efc Improved default text style 2021-10-23 02:59:29 +02:00
Marcin Ziąbek 0a6673dd4f Update QuestPDF.csproj 2021-10-21 15:46:31 +02:00
Marcin Ziąbek 525bf534e5 Update DocumentGenerator.cs 2021-10-19 00:37:07 +02:00
Marcin Ziąbek 68f050a154 Adjusted tests for better benchmarking 2021-10-16 22:34:54 +02:00
Marcin Ziąbek fd696c5b66 Added missing tests to the constrained element 2021-10-12 23:58:28 +02:00
Marcin Ziąbek 0ccc8cc236 Improved the DocumentLayoutException message 2021-10-11 23:01:26 +02:00
Marcin Ziąbek 9ef444462a Implemented the Inlined document 2021-10-11 22:48:44 +02:00
Marcin Ziąbek 479915b68f Implemented the Inlined element 2021-10-11 01:48:12 +02:00
Marcin Ziąbek 5deea91fe4 Code refactorization 2021-10-10 23:21:11 +02:00
Marcin Ziąbek 7174a2afa1 Code style improvements 2021-10-10 19:17:31 +02:00
Marcin Ziąbek 1371fe1df9 Merge pull request #32 from QuestPDF/global-text-style
Global text style
2021-10-10 18:40:19 +02:00
Marcin Ziąbek bb00dfd4d4 Merge pull request #28 from jcl86/main
SkipOnce element for different headers and footers
2021-10-10 18:39:15 +02:00
Marcin Ziąbek 70e5783f0e Updated report sample to follow new text style approach 2021-10-07 23:23:07 +02:00
Marcin Ziąbek e8b7f38187 Fixed setting text style in the text-block-elements 2021-10-07 23:10:12 +02:00
Marcin Ziąbek c2ba2addfc Fixed handling global text style when setting block-wide style 2021-10-07 22:56:51 +02:00
Marcin Ziąbek e379502a64 Implemented prototype of global, document-wide text style 2021-10-07 22:38:41 +02:00
Marcin Ziąbek 88e58500a8 Improved caching 2021-10-07 21:26:14 +02:00
jcl-aadlab caa779e1e0 Added skip element for headers and footers 2021-10-05 10:50:55 +02:00
Marcin Ziąbek 4938e97e6d Update readme.md 2021-10-01 14:09:25 +02:00
Marcin Ziąbek 7980befb77 Synced with 2021.10 2021-10-01 02:32:35 +02:00
Marcin Ziąbek f3b75b43ac Merge branch 'main' of https://github.com/QuestPDF/library into element-proxy
 Conflicts:
	QuestPDF.ReportSample/QuestPDF.ReportSample.csproj
	QuestPDF.ReportSample/Tests.cs
	QuestPDF.UnitTests/ShowOnceTest.cs
	QuestPDF.UnitTests/StackTests.cs
	QuestPDF.UnitTests/TestEngine/Operations/ChildMeasureOperation.cs
	QuestPDF.UnitTests/TestEngine/SingleChildTests.cs
	QuestPDF.UnitTests/TestEngine/TestPlan.cs
	QuestPDF/Drawing/DocumentGenerator.cs
	QuestPDF/Drawing/TextRender.cs
	QuestPDF/Elements/PageBreak.cs
	QuestPDF/Elements/PageNumber.cs
	QuestPDF/Elements/Rotate.cs
	QuestPDF/Elements/Row.cs
	QuestPDF/Elements/Scale.cs
	QuestPDF/Elements/SimpleRotate.cs
	QuestPDF/Elements/Text.cs
	QuestPDF/Elements/Unconstrained.cs
	QuestPDF/Infrastructure/Element.cs
2021-10-01 02:20:21 +02:00
Marcin Ziąbek 17e2727833 Added missing option to style a line 2021-10-01 01:44:53 +02:00
Marcin Ziąbek 1b9ea70f6e Fixed code highlighting 2021-09-30 23:50:34 +02:00
Marcin Ziąbek 87f4c9774a Update readme.md 2021-09-30 23:48:35 +02:00
Marcin Ziąbek 3bdd03031b Updated csproj 2021-09-30 23:08:47 +02:00
Marcin Ziąbek 26335faa97 Improved and fixed old tests 2021-09-30 22:48:39 +02:00
Marcin Ziąbek 7b81e61840 Merge pull request #26 from QuestPDF/richtext
2021.10 Richtext
2021-09-30 22:05:45 +02:00
Marcin Ziąbek 391c5a6092 Merge branch 'main' into richtext 2021-09-30 22:04:47 +02:00
Marcin Ziąbek d951e0a6b2 Removed not needed nuget dependencies 2021-09-19 01:42:52 +02:00
Marcin Ziąbek 188fbc22a7 Added structural tests for: Row, Stack. 2021-09-18 23:40:21 +02:00
Marcin Ziąbek cc6d1c81c8 Updated tests to use FluentAssertions 6 2021-09-18 20:59:21 +02:00
Marcin Ziąbek 6d333da84c Added tests to check simple, container-like constraints for some elements 2021-09-18 01:21:48 +02:00
Marcin Ziąbek e411554a29 Added tests for elements: Box, Layers, Rotate, Scale, SimpleRotate, Translate, Unconstrained 2021-09-18 01:03:58 +02:00
Marcin Ziąbek 9fddea84ba Cleaned tests suite 2021-09-17 22:05:07 +02:00
Marcin Ziąbek 84e896e13b 2021.10.0-beta.2 Improved API naming 2021-09-14 12:16:49 +02:00
Marcin Ziąbek 569864d48a Fixed rendering text when put in the Box element 2021-09-14 02:13:15 +02:00
Marcin Ziąbek 2c11491d4e Library update 2021-09-14 02:02:45 +02:00
Marcin Ziąbek acdd8164be Optimized the TextLine object 2021-09-14 00:16:16 +02:00
Marcin Ziąbek 094b25a9fb Merge remote-tracking branch 'origin/richtext' into richtext
# Conflicts:
#	QuestPDF.Examples/QuestPDF.Examples.csproj
#	QuestPDF/Drawing/DocumentGenerator.cs
#	QuestPDF/Drawing/FontManager.cs
#	QuestPDF/Elements/Text/Items/TextBlockSpan.cs
2021-09-13 20:38:50 +02:00
Marcin Ziąbek 122f35d0a7 2021.10-beta + Code rebase 2021-09-13 20:36:29 +02:00
Marcin Ziąbek f4c9f8b3c2 Added text rendering tests 2021-09-13 20:30:18 +02:00
Marcin Ziąbek ae7873680d Fixed layout rendering 2021-09-13 20:30:16 +02:00
Marcin Ziąbek 175db288f6 Improved text measuring performance 2021-09-13 20:29:53 +02:00
Marcin Ziąbek 22401be791 Fixed rendering spaces, fixed text alignment 2021-09-13 20:29:53 +02:00
Marcin Ziąbek e2774ef347 Improved book layout in benchmark 2021-09-13 20:29:53 +02:00
Marcin Ziąbek 99f004dd85 Improved text rendering (space corner cases) 2021-09-13 20:29:53 +02:00
Marcin Ziąbek 8ada092531 Fixed text rendering (spacing corner case) 2021-09-13 20:29:53 +02:00
Marcin Ziąbek c334390af0 Better new line handling 2021-09-13 20:29:53 +02:00
Marcin Ziąbek deed219a0a Code structure improvements. Text rendering: support for words longer than available space 2021-09-13 20:29:53 +02:00
Marcin Ziąbek bb8e590fc6 Code structure improvements 2021-09-13 20:29:53 +02:00
Marcin Ziąbek a08a7b85c9 Example report fixes 2021-09-13 20:29:52 +02:00
Marcin Ziąbek 755447e1fd Text: rendering custom elements inside text 2021-09-13 20:29:52 +02:00
Marcin Ziąbek b66a53a189 Text component: internal and external links 2021-09-13 20:29:52 +02:00
Marcin Ziąbek 6d41ac9b9a Fix: the Stack may not show last an element in certain scenarios 2021-09-13 20:29:52 +02:00
Marcin Ziąbek a124d23862 Code cleanup 2021-09-13 20:29:50 +02:00
Marcin Ziąbek 5f65b2daed Text Rendering Optimization: Caching Measurement Results 2021-09-13 20:29:44 +02:00
Marcin Ziąbek 07938a1510 Text rendering optimization: style key, font metrics caching 2021-09-13 20:29:34 +02:00
Marcin Ziąbek f17860f519 Implemented text rendering benchmark 2021-09-13 20:29:24 +02:00
Marcin Ziąbek 6023b4de34 Improved text rendering capabilities 2021-09-13 20:29:17 +02:00
Marcin Ziąbek 748b8f65f5 Initial text rendering improvements 2021-09-13 20:29:17 +02:00
Marcin Ziąbek feab280a27 Fixed detecting infinite layout exception in specific cases 2021-09-13 01:09:45 +02:00
Marcin Ziąbek ae32511172 Added text rendering tests 2021-09-13 01:06:06 +02:00
Marcin Ziąbek 6c4da7285a Fixed layout rendering 2021-09-13 00:55:21 +02:00
Marcin Ziąbek 070b6a20bd Improved text measuring performance 2021-09-12 21:37:46 +02:00
Marcin Ziąbek f7cfdb763f Fixed rendering spaces, fixed text alignment 2021-09-12 21:01:10 +02:00
Marcin Ziąbek 5975b19445 Improved book layout in benchmark 2021-09-07 13:34:04 +02:00
Marcin Ziąbek fb7743e828 Improved text rendering (space corner cases) 2021-09-07 13:16:34 +02:00
Marcin Ziąbek eca93b7e66 Added debug pointers to page 2021-09-07 11:17:49 +02:00
Marcin Ziąbek 6a3bfd855e Improved infinite layout debugging experience 2021-09-07 00:32:51 +02:00
Marcin Ziąbek 5e7f2a3adf Simple layout debugging when overflow 2021-09-06 21:43:31 +02:00
Marcin Ziąbek 2f1dd4b383 Improved tests with Benchmark.net 2021-09-06 21:43:12 +02:00
Marcin Ziąbek adec37007b Refactorization: space planning algorithm 2021-09-02 21:48:20 +02:00
Marcin Ziąbek 814d325376 Implemented measurement cache proxy 2021-09-02 13:30:39 +02:00
Marcin Ziąbek 4152a0f701 Improved row performance and layout structure stability 2021-09-02 00:53:50 +02:00
Marcin Ziąbek 6c80c59996 Fixed misspelling in release notes 2021-09-01 19:19:16 +02:00
Marcin Ziąbek 08a37666fe 2021.9.1 2021-09-01 19:14:52 +02:00
Marcin Ziąbek c2fb68562d 2021.9.0 2021-08-30 23:37:44 +02:00
Marcin Ziąbek 683ab362d8 Added support for registering font types based on the suggestion of brendonparker 2021-08-29 20:15:12 +02:00
Marcin Ziąbek 3bb46ecc42 Fixed text rendering (spacing corner case) 2021-08-29 19:18:58 +02:00
Marcin Ziąbek 3112ee10cf Better new line handling 2021-08-27 20:25:20 +02:00
Marcin Ziąbek 899c138842 Code structure improvements. Text rendering: support for words longer than available space 2021-08-27 19:51:28 +02:00
Marcin Ziąbek 5177dcfd2b Code structure improvements 2021-08-27 12:40:06 +02:00
Marcin Ziąbek 4e6415aee2 Example report fixes 2021-08-27 11:40:33 +02:00
Marcin Ziąbek d9b3f016e8 Text: rendering custom elements inside text 2021-08-27 01:55:20 +02:00
Marcin Ziąbek b9cfaf3846 Text component: internal and external links 2021-08-27 01:38:26 +02:00
Marcin Ziąbek e3e7a22af8 Fix: the Stack may not show last an element in certain scenarios 2021-08-27 01:38:10 +02:00
Marcin Ziąbek c938ea32b0 Code cleanup 2021-08-27 01:10:30 +02:00
Marcin Ziąbek 69419c8440 Text Rendering Optimization: Caching Measurement Results 2021-08-27 00:29:04 +02:00
Marcin Ziąbek 23e8aa3491 Text rendering optimization: style key, font metrics caching 2021-08-26 23:36:43 +02:00
Marcin Ziąbek fd5d51e764 Implemented text rendering benchmark 2021-08-26 22:25:33 +02:00
Marcin Ziąbek dbc479db07 Improved text rendering capabilities 2021-08-25 03:40:16 +02:00
Marcin Ziąbek 04af33fc31 Included examples for DSL and complex layouts 2021-08-23 23:51:42 +02:00
Marcin Ziąbek edc595d199 Initial text rendering improvements 2021-08-09 22:35:39 +02:00
Marcin Ziąbek 7f94ae589a Updated release notes and code example 2021-08-03 01:43:48 +02:00
Marcin Ziąbek adfce6204e Improved testing environment by adding proper result files names, Added more code examples 2021-08-03 01:35:46 +02:00
Marcin Ziąbek 6d3c8d0708 Added elements: Rotate, Unconstrained 2021-08-01 21:09:16 +02:00
Marcin Ziąbek 3b8c300126 Merge pull request #17 from QuestPDF/2021.6
Merge 2021.6 for QuestPdf 2021.8
2021-08-01 16:58:44 +02:00
Marcin Ziąbek 20fe49dd01 Update SECURITY.md 2021-07-18 18:10:55 +02:00
Marcin Ziąbek 7cdc1fcee2 Create SECURITY.md 2021-07-18 18:10:20 +02:00
Marcin Ziąbek c05c5e1597 Update readme.md
Updated code, added the support section
2021-05-15 16:09:01 +02:00
372 changed files with 25604 additions and 3773 deletions
+70
View File
@@ -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
+54
View File
@@ -0,0 +1,54 @@
name: Build And Create Nuget Package
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
schedule:
- cron: '3 0 * * 0'
jobs:
main:
runs-on: ${{ matrix.environment }}
strategy:
matrix:
environment:
- macos-latest
- ubuntu-latest
- windows-latest
env:
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
UNIT_TEST_PROJECT: QuestPDF.UnitTests/QuestPDF.UnitTests.csproj
steps:
- name: 📝 Fetch Sources 📝
uses: actions/checkout@v2
- name: ⚙ Setup .NET 6.0 SDK ⚙
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
- name: 🔄 Restore Nuget Packages 🔄
shell: bash
run: dotnet restore
working-directory: ./Source
- name: 🛠 Build Solution 🛠
shell: bash
run: dotnet build -c Release --no-restore
working-directory: ./Source
- name: Upload build artifacts
uses: actions/upload-artifact@v3
if: ${{ matrix.environment == 'windows-latest' }}
with:
name: Build Package
path: |
**/*.nupkg
**/*.snupkg
!.nuget
+1
View File
@@ -0,0 +1 @@
github: QuestPDF
View File
-51
View File
@@ -1,51 +0,0 @@
using System;
using System.Diagnostics;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples.Engine
{
public class RenderingTest
{
private string FileNamePrefix = "test";
private Size Size { get; set; }
private RenderingTest()
{
}
public static RenderingTest Create()
{
return new RenderingTest();
}
public RenderingTest FileName(string fileName)
{
FileNamePrefix = fileName;
return this;
}
public RenderingTest PageSize(int width, int height)
{
Size = new Size(width, height);
return this;
}
public void Render(Action<IContainer> content)
{
var container = new Container();
content(container);
Func<int, string> fileNameSchema = i => $"{FileNamePrefix}-${i}.png";
var document = new SimpleDocument(container, Size);
document.GenerateImages(fileNameSchema);
Process.Start("explorer", fileNameSchema(0));
}
}
}
@@ -1,40 +0,0 @@
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples.Engine
{
public class SimpleDocument : IDocument
{
public const int ImageScalingFactor = 2;
private IContainer Container { get; }
private Size Size { get; }
public SimpleDocument(IContainer container, Size size)
{
Container = container;
Size = size;
}
public DocumentMetadata GetMetadata()
{
return new DocumentMetadata()
{
RasterDpi = PageSizes.PointsPerInch * ImageScalingFactor,
DocumentLayoutExceptionThreshold = 10
};
}
public void Compose(IDocumentContainer container)
{
container.Page(page =>
{
page.Size(new PageSize(Size.Width, Size.Height));
page.Content().Container().Element(Container as Container);
});
}
}
}
@@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
</ItemGroup>
</Project>
-28
View File
@@ -1,28 +0,0 @@
using System;
using System.IO;
using SkiaSharp;
namespace QuestPDF.ReportSample
{
public static class Helpers
{
public static Random Random { get; } = new Random();
public static string GetTestItem(string path) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", path);
public static byte[] GetImage(string name)
{
var photoPath = GetTestItem(name);
return SKImage.FromEncodedData(photoPath).EncodedData.ToArray();
}
public static Location RandomLocation()
{
return new Location
{
Longitude = Helpers.Random.NextDouble() * 360f - 180f,
Latitude = Helpers.Random.NextDouble() * 180f - 90f
};
}
}
}
@@ -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,50 +0,0 @@
using System.Collections.Generic;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
namespace QuestPDF.ReportSample.Layouts
{
public class TableOfContentsTemplate : IComponent
{
private List<ReportSection> Sections { get; }
public TableOfContentsTemplate(List<ReportSection> sections)
{
Sections = sections;
}
public void Compose(IContainer container)
{
container
.Decoration(decoration =>
{
decoration
.Header()
.PaddingBottom(5)
.Text("Table of contents", Typography.Headline);
decoration.Content().Stack(stack =>
{
stack.Spacing(5);
for (var i = 0; i < Sections.Count; i++)
stack.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
stack.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
});
});
}
private void DrawLink(IContainer container, int number, string locationName)
{
container
.InternalLink(locationName)
.Row(row =>
{
row.ConstantColumn(25).Text($"{number}.", Typography.Normal);
row.RelativeColumn().Text(locationName, Typography.Normal);
row.ConstantColumn(150).AlignRight().PageNumber($"Page {{pdf:{locationName}}}", Typography.Normal.AlignRight());
});
}
}
}
-64
View File
@@ -1,64 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Fluent;
using QuestPDF.ReportSample.Layouts;
namespace QuestPDF.ReportSample
{
public class ReportGeneration
{
[Test]
public void GenerateAndShow()
{
var reportModel = DataSource.GetReport();
var report = new StandardReport(reportModel);
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
report.GeneratePdf(path);
Process.Start("explorer.exe", path);
}
[Test]
public void PerformanceBenchmark()
{
// target document length should be around 100 pages
// test size
const int testSize = 100;
const decimal performanceTarget = 1; // 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();
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 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");
if (speed < performanceTarget)
throw new Exception("Rendering algorithm is too slow.");
}
}
}
-98
View File
@@ -1,98 +0,0 @@
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class ConstrainedTests
{
[Test]
public void Measure_ShouldHandleNullChild() => new Constrained().MeasureWithoutChild();
[Test]
public void Draw_ShouldHandleNullChild() => new Constrained().DrawWithoutChild();
[Test]
public void Measure_MinHeight_ExpectWrap()
{
TestPlan
.For(x => new Constrained
{
MinHeight = 100
})
.MeasureElement(new Size(400, 50))
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_MinHeight_ExtendHeight()
{
TestPlan
.For(x => new Constrained
{
MinHeight = 100,
Child = x.CreateChild()
})
.MeasureElement(new Size(400, 200))
.ExpectChildMeasure(new Size(400, 200), new FullRender(400, 50))
.CheckMeasureResult(new FullRender(400, 100));
}
[Test]
public void Measure_MinHeight_PassHeight()
{
TestPlan
.For(x => new Constrained
{
MinHeight = 100,
Child = x.CreateChild()
})
.MeasureElement(new Size(400, 200))
.ExpectChildMeasure(new Size(400, 200), new FullRender(400, 150))
.CheckMeasureResult(new FullRender(400, 150));
}
[Test]
public void Measure_MaxHeight_Empty()
{
TestPlan
.For(x => new Constrained
{
MaxHeight = 100
})
.MeasureElement(new Size(400, 150))
.CheckMeasureResult(new FullRender(0, 0));
}
[Test]
public void Measure_MaxHeight_PartialRender()
{
TestPlan
.For(x => new Constrained
{
MaxHeight = 100,
Child = x.CreateChild()
})
.MeasureElement(new Size(400, 200))
.ExpectChildMeasure(new Size(400, 100), new PartialRender(400, 75))
.CheckMeasureResult(new PartialRender(400, 75));
}
[Test]
public void Measure_MaxHeight_ExpectWrap()
{
TestPlan
.For(x => new Constrained
{
MaxHeight = 100,
Child = x.CreateChild()
})
.MeasureElement(new Size(400, 200))
.ExpectChildMeasure(new Size(400, 100), new Wrap())
.CheckMeasureResult(new Wrap());
}
}
}
-10
View File
@@ -1,10 +0,0 @@
using NUnit.Framework;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class DebugTests
{
}
}
-136
View File
@@ -1,136 +0,0 @@
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class DecorationTests
{
#region Measure
[Test]
public void Measure_ReturnsWrap_WhenDecorationReturnsWrap()
{
TestPlan
.For(x => new SimpleDecoration
{
Type = DecorationType.Append,
DecorationElement = x.CreateChild("decoration"),
ContentElement = x.CreateChild("content")
})
.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());
}
[Test]
public void Measure_ReturnsWrap_WhenContentReturnsWrap()
{
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 FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), new Wrap())
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_ReturnsPartialRender_WhenContentReturnsPartialRender()
{
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 FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), new PartialRender(200, 150))
.CheckMeasureResult(new PartialRender(400, 250));
}
[Test]
public void Measure_ReturnsFullRender_WhenContentReturnsFullRender()
{
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 FullRender(300, 100))
.ExpectChildMeasure("content", new Size(400, 200), new FullRender(200, 150))
.CheckMeasureResult(new FullRender(400, 250));
}
#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")
})
.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)
.CheckDrawResult();
}
#endregion
}
}
-30
View File
@@ -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());
});
}
}
}
-68
View File
@@ -1,68 +0,0 @@
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
using SkiaSharp;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class ImageTests
{
[Test]
public void Measure_ShouldHandleNullChild() => new AspectRatio().MeasureWithoutChild();
[Test]
public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
[Test]
public void Measure_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new Image
{
InternalImage = GenerateImage(400, 300)
})
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(new FullRender(300, 200));
}
[Test]
public void Draw_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new Image
{
InternalImage = GenerateImage(400, 300)
})
.DrawElement(new Size(300, 200))
.ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))
.CheckDrawResult();
}
[Test]
public void Fluent_RecognizesImageProportions()
{
var image = GenerateImage(600, 200).Encode(SKEncodedImageFormat.Png, 100).ToArray();
TestPlan
.For(x =>
{
var container = new Container();
container.Image(image);
return container;
})
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(new FullRender(300, 100));;
}
SKImage GenerateImage(int width, int height)
{
var imageInfo = new SKImageInfo(width, height);
using var surface = SKSurface.Create(imageInfo);
return surface.Snapshot();
}
}
}
-10
View File
@@ -1,10 +0,0 @@
using NUnit.Framework;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class PageNumberTests
{
}
}
@@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="nunit" Version="3.13.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
</ItemGroup>
</Project>
-116
View File
@@ -1,116 +0,0 @@
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class RowTests
{
#region Measure
[Test]
public void Measure_ReturnsWrap_WhenLeftChildReturnsWrap()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new Wrap())
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_ReturnsWrap_WhenRightChildReturnsWrap()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), new Wrap())
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_ReturnsPartialRender_WhenLeftChildReturnsPartialRender()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new PartialRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), new FullRender(100, 100))
.CheckMeasureResult(new PartialRender(350, 150));
}
[Test]
public void Measure_ReturnsPartialRender_WhenRightChildReturnsPartialRender()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
.ExpectChildMeasure("right", new Size(150, 300), new PartialRender(100, 100))
.CheckMeasureResult(new PartialRender(350, 150));
}
[Test]
public void Measure_ReturnsFullRender_WhenBothChildrenReturnFullRender()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(200, 150))
.ExpectChildMeasure("right", new Size(200, 300), new FullRender(100, 100))
.CheckMeasureResult(new FullRender(300, 150));
}
#endregion
#region Draw
[Test]
public void Draw()
{
TestPlan
.For(x => new SimpleRow
{
Left = x.CreateChild("left"),
Right = x.CreateChild("right")
})
.DrawElement(new Size(400, 300))
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
.ExpectChildDraw("left", new Size(250, 300))
.ExpectCanvasTranslate(250, 0)
.ExpectChildDraw("right", new Size(150, 300))
.ExpectCanvasTranslate(-250, 0)
.CheckDrawResult();
}
#endregion
// TODO: add tests for the spacing property
// TODO: add tests for the tree builder method
// TODO: add tests for relative column
}
}
@@ -1,44 +0,0 @@
using System;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.UnitTests.TestEngine
{
internal class CanvasMock : ICanvas
{
public Action<Position> TranslateFunc { get; set; }
public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
public Action<Position, Size, string> DrawRectFunc { get; set; }
public void Translate(Position vector) => TranslateFunc(vector);
public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
public void DrawExternalLink(string url, Size size)
{
throw new NotImplementedException();
}
public void DrawLocationLink(string locationName, Size size)
{
throw new NotImplementedException();
}
public void DrawLocation(string locationName)
{
throw new NotImplementedException();
}
public void DrawLink(string url, Size size)
{
throw new NotImplementedException();
}
public Size MeasureText(string text, TextStyle style)
{
return new Size(text.Length * style.Size, style.Size);
}
}
}
@@ -1,31 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
namespace QuestPDF.UnitTests.TestEngine
{
public static class SingleChildTests
{
internal static void MeasureWithoutChild<T>(this T element) where T : ContainerElement
{
element.Child = null;
element.Measure(Size.Zero).Should().BeEquivalentTo(new FullRender(Size.Zero));
}
internal static void DrawWithoutChild<T>(this T element) where T : ContainerElement
{
// component does not throw an exception when called with null child
Assert.DoesNotThrow(() =>
{
element.Child = null;
// component does not perform any canvas operation when called with null child
TestPlan
.For(x => element)
.DrawElement(new Size(200, 100))
.CheckDrawResult();
});
}
}
}
-10
View File
@@ -1,10 +0,0 @@
using NUnit.Framework;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class TextTests
{
}
}
-5
View File
@@ -1,5 +0,0 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("QuestPDF.UnitTests")]
[assembly: InternalsVisibleTo("QuestPDF.Examples")]
-63
View File
@@ -1,63 +0,0 @@
using System.Collections.Concurrent;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Drawing
{
internal static class CanvasCache
{
private static ConcurrentDictionary<string, SKPaint> Paints = new ConcurrentDictionary<string, SKPaint>();
private static ConcurrentDictionary<string, SKPaint> ColorPaint = new ConcurrentDictionary<string, SKPaint>();
internal static SKPaint ColorToPaint(this string color)
{
return ColorPaint.GetOrAdd(color, Convert);
static SKPaint Convert(string color)
{
return new SKPaint
{
Color = SKColor.Parse(color)
};
}
}
internal static SKPaint ToPaint(this TextStyle style)
{
return Paints.GetOrAdd(style.ToString(), key => Convert(style));
static SKPaint Convert(TextStyle style)
{
var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
return new SKPaint
{
Color = SKColor.Parse(style.Color),
Typeface = SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant),
TextSize = style.Size,
TextEncoding = SKTextEncoding.Utf32,
TextAlign = style.Alignment switch
{
HorizontalAlignment.Left => SKTextAlign.Left,
HorizontalAlignment.Center => SKTextAlign.Center,
HorizontalAlignment.Right => SKTextAlign.Right,
_ => SKTextAlign.Left
}
};
}
}
internal static TextMeasurement BreakText(this TextStyle style, string text, float availableWidth)
{
var index = (int)style.ToPaint().BreakText(text, availableWidth, out var width);
return new TextMeasurement()
{
LineIndex = index,
FragmentWidth = width
};
}
}
}
-93
View File
@@ -1,93 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Drawing
{
static class DocumentGenerator
{
internal static void GeneratePdf(Stream stream, IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new PdfCanvas(stream, metadata);
RenderDocument(canvas, document);
}
internal static ICollection<byte[]> GenerateImages(IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new ImageCanvas(metadata);
RenderDocument(canvas, document);
return canvas.Images;
}
private static void RenderDocument<TCanvas>(TCanvas canvas, IDocument document)
where TCanvas : ICanvas, IRenderingCanvas
{
var container = new DocumentContainer();
document.Compose(container);
var content = container.Compose();
var metadata = document.GetMetadata();
var pageContext = new PageContext();
RenderPass(pageContext, new FreeCanvas(), content, metadata);
RenderPass(pageContext, canvas, content, metadata);
}
private static void RenderPass<TCanvas>(PageContext pageContext, TCanvas canvas, Container content, DocumentMetadata documentMetadata)
where TCanvas : ICanvas, IRenderingCanvas
{
content.HandleVisitor(x => x?.Initialize(pageContext, canvas));
content.HandleVisitor(x => (x as IStateResettable)?.ResetState());
canvas.BeginDocument();
var currentPage = 1;
while(true)
{
pageContext.SetPageNumber(currentPage);
var spacePlan = content.Measure(Size.Max) as Size;
if (spacePlan == null)
break;
try
{
canvas.BeginPage(spacePlan);
content.Draw(spacePlan);
}
catch (Exception exception)
{
canvas.EndDocument();
throw new DocumentDrawingException("An exception occured during document drawing.", exception);
}
canvas.EndPage();
if (currentPage >= documentMetadata.DocumentLayoutExceptionThreshold)
{
canvas.EndDocument();
throw new DocumentLayoutException("Composed layout generates infinite document.");
}
if (spacePlan is FullRender)
break;
currentPage++;
}
canvas.EndDocument();
}
}
}
-31
View File
@@ -1,31 +0,0 @@
using System;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Drawing
{
public class DocumentMetadata
{
public int ImageQuality { get; set; } = 101;
public int RasterDpi { get; set; } = 72;
public bool PdfA { get; set; }
public string? Title { get; set; }
public string? Author { get; set; }
public string? Subject { get; set; }
public string? Keywords { get; set; }
public string? Creator { get; set; }
public string? Producer { get; set; }
public DateTime CreationDate { get; set; } = DateTime.Now;
public DateTime ModifiedDate { get; set; } = DateTime.Now;
/// <summary>
/// If the number of generated pages exceeds this threshold
/// (likely due to infinite layout), the exception is thrown.
/// </summary>
public int DocumentLayoutExceptionThreshold { get; set; } = 250;
public static DocumentMetadata Default => new DocumentMetadata();
}
}
@@ -1,22 +0,0 @@
using System;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentComposeException : Exception
{
public DocumentComposeException()
{
}
public DocumentComposeException(string message) : base(message)
{
}
public DocumentComposeException(string message, Exception inner) : base(message, inner)
{
}
}
}
@@ -1,22 +0,0 @@
using System;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentDrawingException : Exception
{
public DocumentDrawingException()
{
}
public DocumentDrawingException(string message) : base(message)
{
}
public DocumentDrawingException(string message, Exception inner) : base(message, inner)
{
}
}
}
@@ -1,22 +0,0 @@
using System;
namespace QuestPDF.Drawing.Exceptions
{
public class DocumentLayoutException : Exception
{
public DocumentLayoutException()
{
}
public DocumentLayoutException(string message) : base(message)
{
}
public DocumentLayoutException(string message, Exception inner) : base(message, inner)
{
}
}
}
-19
View File
@@ -1,19 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Drawing.SpacePlan
{
internal class FullRender : Size, ISpacePlan
{
public FullRender(Size size) : this(size.Width, size.Height)
{
}
public FullRender(float width, float height) : base(width, height)
{
}
public override string ToString() => $"FullRender {base.ToString()}";
}
}
-7
View File
@@ -1,7 +0,0 @@
namespace QuestPDF.Drawing.SpacePlan
{
internal interface ISpacePlan
{
}
}
@@ -1,19 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Drawing.SpacePlan
{
internal class PartialRender : Size, ISpacePlan
{
public PartialRender(Size size) : this(size.Width, size.Height)
{
}
public PartialRender(float width, float height) : base(width, height)
{
}
public override string ToString() => $"PartialRender {base.ToString()}";
}
}
@@ -1,8 +0,0 @@
namespace QuestPDF.Drawing.SpacePlan
{
internal struct TextMeasurement
{
public int LineIndex { get; set; }
public float FragmentWidth { get; set; }
}
}
-7
View File
@@ -1,7 +0,0 @@
namespace QuestPDF.Drawing.SpacePlan
{
internal class Wrap : ISpacePlan
{
public override string ToString() => "Wrap";
}
}
-17
View File
@@ -1,17 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Box : ContainerElement
{
internal override void Draw(Size availableSpace)
{
var targetSize = Child?.Measure(availableSpace) as Size;
if (targetSize == null)
return;
Child?.Draw(targetSize);
}
}
}
-69
View File
@@ -1,69 +0,0 @@
using System;
using System.Linq;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Constrained : ContainerElement
{
public float? MinWidth { get; set; }
public float? MaxWidth { get; set; }
public float? MinHeight { get; set; }
public float? MaxHeight { get; set; }
internal override ISpacePlan Measure(Size availableSpace)
{
if (MinWidth > availableSpace.Width + Size.Epsilon)
return new Wrap();
if (MinHeight > availableSpace.Height + Size.Epsilon)
return new Wrap();
var available = new Size(
MathHelpers.Min(MaxWidth, availableSpace.Width),
MathHelpers.Min(MaxHeight, availableSpace.Height));
var measurement = Child?.Measure(available) ?? new FullRender(Size.Zero);
var size = measurement as Size;
if (measurement is Wrap)
return new Wrap();
var actualSize = new Size(
MathHelpers.Max(MinWidth, size.Width),
MathHelpers.Max(MinHeight, size.Height));
if (size is FullRender)
return new FullRender(actualSize);
if (size is PartialRender)
return new PartialRender(actualSize);
throw new NotSupportedException();
}
internal override void Draw(Size availableSpace)
{
var available = new Size(
MathHelpers.Min(MaxWidth, availableSpace.Width),
MathHelpers.Min(MaxHeight, availableSpace.Height));
Child?.Draw(available);
}
}
static class MathHelpers
{
public static float Min(params float?[] values)
{
return values.Where(x => x.HasValue).Min().Value;
}
public static float Max(params float?[] values)
{
return values.Where(x => x.HasValue).Max().Value;
}
}
}
-93
View File
@@ -1,93 +0,0 @@
using System;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal enum DecorationType
{
Prepend,
Append
}
internal class SimpleDecoration : Element
{
public Element DecorationElement { get; set; } = Empty.Instance;
public Element ContentElement { get; set; } = Empty.Instance;
public DecorationType Type { get; set; }
internal override void HandleVisitor(Action<Element?> visit)
{
DecorationElement?.HandleVisitor(visit);
ContentElement?.HandleVisitor(visit);
base.HandleVisitor(visit);
}
internal override ISpacePlan Measure(Size availableSpace)
{
var decorationMeasure = DecorationElement?.Measure(availableSpace);
if (decorationMeasure is Wrap || decorationMeasure is PartialRender)
return new Wrap();
var decorationSize = decorationMeasure as Size ?? Size.Zero;
var contentMeasure = ContentElement?.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)) ?? new FullRender(Size.Zero);
if (contentMeasure is Wrap)
return new Wrap();
var contentSize = contentMeasure as Size ?? Size.Zero;
var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height);
if (contentSize is PartialRender)
return new PartialRender(resultSize);
if (contentSize is FullRender)
return new FullRender(resultSize);
throw new NotSupportedException();
}
internal override void Draw(Size availableSpace)
{
var decorationSize = DecorationElement?.Measure(availableSpace) as Size ?? Size.Zero;
var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height);
var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height;
Action drawDecoration = () => DecorationElement?.Draw(new Size(availableSpace.Width, decorationSize.Height));
Action drawContent = () => ContentElement?.Draw(new Size (availableSpace.Width, contentSize.Height));
var first = Type == DecorationType.Prepend ? drawDecoration : drawContent;
var second = Type == DecorationType.Prepend ? drawContent : drawDecoration;
first();
Canvas.Translate(new Position(0, translateHeight));
second();
Canvas.Translate(new Position(0, -translateHeight));
}
}
internal class Decoration : IComponent
{
public Element Header { get; set; } = Empty.Instance;
public Element Content { get; set; } = Empty.Instance;
public Element Footer { get; set; } = Empty.Instance;
public void Compose(IContainer container)
{
container.Element(new SimpleDecoration
{
Type = DecorationType.Prepend,
DecorationElement = Header,
ContentElement = new SimpleDecoration
{
Type = DecorationType.Append,
ContentElement = Content,
DecorationElement = Footer
}
});
}
}
}
-20
View File
@@ -1,20 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class ExternalLink : ContainerElement
{
public string Url { get; set; } = "https://www.questpdf.com";
internal override void Draw(Size availableSpace)
{
var targetSize = Child?.Measure(availableSpace) as Size;
if (targetSize == null)
return;
Canvas.DrawExternalLink(Url, targetSize);
Child?.Draw(availableSpace);
}
}
}
-29
View File
@@ -1,29 +0,0 @@
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Elements
{
internal class Image : Element
{
public SKImage? InternalImage { get; set; }
~Image()
{
InternalImage?.Dispose();
}
internal override ISpacePlan Measure(Size availableSpace)
{
return new FullRender(availableSpace);
}
internal override void Draw(Size availableSpace)
{
if (InternalImage == null)
return;
Canvas.DrawImage(InternalImage, Position.Zero, availableSpace);
}
}
}
-20
View File
@@ -1,20 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class InternalLink : ContainerElement
{
public string LocationName { get; set; }
internal override void Draw(Size availableSpace)
{
var targetSize = Child?.Measure(availableSpace) as Size;
if (targetSize == null)
return;
Canvas.DrawLocationLink(LocationName, targetSize);
Child?.Draw(availableSpace);
}
}
}
-44
View File
@@ -1,44 +0,0 @@
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Page : IComponent
{
public Size MinSize { get; set; } = PageSizes.A4;
public Size MaxSize { get; set; } = PageSizes.A4;
public float MarginLeft { get; set; }
public float MarginRight { get; set; }
public float MarginTop { get; set; }
public float MarginBottom { get; set; }
public Element Header { get; set; } = Empty.Instance;
public Element Content { get; set; } = Empty.Instance;
public Element Footer { get; set; } = Empty.Instance;
public void Compose(IContainer container)
{
container
.MinWidth(MinSize.Width)
.MinHeight(MinSize.Height)
.MaxWidth(MaxSize.Width)
.MaxHeight(MaxSize.Height)
.PaddingLeft(MarginLeft)
.PaddingRight(MarginRight)
.PaddingTop(MarginTop)
.PaddingBottom(MarginBottom)
.Decoration(decoration =>
{
decoration.Header().Element(Header);
decoration.Content().Extend().Element(Content);
decoration.Footer().Element(Footer);
});
}
}
}
-52
View File
@@ -1,52 +0,0 @@
using System;
using System.Text.RegularExpressions;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using Size = QuestPDF.Infrastructure.Size;
namespace QuestPDF.Elements
{
internal class PageNumber : Element
{
public string TextFormat { get; set; } = "";
private Text TextElement { get; set; } = new Text();
public TextStyle? TextStyle
{
get => TextElement?.Style;
set => TextElement.Style = value;
}
internal override void HandleVisitor(Action<Element?> visit)
{
TextElement?.HandleVisitor(visit);
base.HandleVisitor(visit);
}
internal override ISpacePlan Measure(Size availableSpace)
{
TextElement.Value = GetText();
return TextElement.Measure(availableSpace);
}
internal override void Draw(Size availableSpace)
{
TextElement.Value = GetText();
TextElement.Draw(availableSpace);
}
private string GetText()
{
var result = TextFormat;
// replace known locations
foreach (var location in PageContext.GetRegisteredLocations())
result = result.Replace($"{{pdf:{location}}}", PageContext.GetLocationPage(location).ToString());
// placeholder unknown locations
result = Regex.Replace(result, @"{pdf:[ \w]+}", "123");
return result;
}
}
}
-59
View File
@@ -1,59 +0,0 @@
using System;
using System.Linq;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Rotate : ContainerElement
{
public int TurnCount { get; set; }
public int NormalizedTurnCount => (TurnCount % 4 + 4) % 4;
internal override ISpacePlan Measure(Size availableSpace)
{
if (NormalizedTurnCount == 0 || NormalizedTurnCount == 2)
return base.Measure(availableSpace);
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
var childSpace = base.Measure(availableSpace) as Size;
if (childSpace == null)
return new Wrap();
var targetSpace = new Size(childSpace.Height, childSpace.Width);
if (childSpace is FullRender)
return new FullRender(targetSpace);
if (childSpace is PartialRender)
return new PartialRender(targetSpace);
throw new ArgumentException();
}
internal override void Draw(Size availableSpace)
{
var skiaCanvas = (Canvas as Drawing.SkiaCanvasBase)?.Canvas;
if (skiaCanvas == null)
return;
var currentMatrix = skiaCanvas.TotalMatrix;
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 2)
skiaCanvas.Translate(availableSpace.Width, 0);
if (NormalizedTurnCount == 2 || NormalizedTurnCount == 3)
skiaCanvas.Translate(0, availableSpace.Height);
skiaCanvas.RotateRadians(NormalizedTurnCount * (float) Math.PI / 2f);
if (NormalizedTurnCount == 1 || NormalizedTurnCount == 3)
availableSpace = new Size(availableSpace.Height, availableSpace.Width);
Child?.Draw(availableSpace);
skiaCanvas.SetMatrix(currentMatrix);
}
}
}
-183
View File
@@ -1,183 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal abstract class RowElement : ContainerElement
{
public float Width { get; set; } = 1;
internal override void Draw(Size availableSpace)
{
Child?.Draw(availableSpace);
}
}
internal class ConstantRowElement : RowElement
{
public ConstantRowElement(float width)
{
Width = width;
}
}
internal class RelativeRowElement : RowElement
{
public RelativeRowElement(float width)
{
Width = width;
}
}
internal class SimpleRow : Element
{
internal Element Left { get; set; }
internal Element Right { get; set; }
internal override void HandleVisitor(Action<Element?> visit)
{
Left.HandleVisitor(visit);
Right.HandleVisitor(visit);
base.HandleVisitor(visit);
}
internal override ISpacePlan Measure(Size availableSpace)
{
var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)) as Size;
if (leftMeasurement == null)
return new Wrap();
var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height)) as Size;
if (rightMeasurement == null)
return new Wrap();
var totalWidth = leftMeasurement.Width + rightMeasurement.Width;
var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height);
var targetSize = new Size(totalWidth, totalHeight);
if (leftMeasurement is PartialRender || rightMeasurement is PartialRender)
return new PartialRender(targetSize);
return new FullRender(targetSize);
}
internal override void Draw(Size availableSpace)
{
var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height));
var leftWidth = (leftMeasurement as Size)?.Width ?? 0;
Left.Draw(new Size(leftWidth, availableSpace.Height));
Canvas.Translate(new Position(leftWidth, 0));
Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height));
Canvas.Translate(new Position(-leftWidth, 0));
}
}
internal class Row : Element
{
public ICollection<RowElement> Children { get; internal set; } = new List<RowElement>();
public float Spacing { get; set; } = 0;
internal override void HandleVisitor(Action<Element?> visit)
{
Children.ToList().ForEach(x => x.HandleVisitor(visit));
base.HandleVisitor(visit);
}
internal override ISpacePlan Measure(Size availableSpace)
{
return Compose(availableSpace.Width).Measure(availableSpace);
}
internal override void Draw(Size availableSpace)
{
Compose(availableSpace.Width).Draw(availableSpace);
}
#region structure
private Element Compose(float availableWidth)
{
var elements = AddSpacing(Children, Spacing);
var rowElements = ReduceRows(elements, availableWidth);
var tree = BuildTree(rowElements.ToArray());
tree.HandleVisitor(x => x.Initialize(PageContext, Canvas));
return tree;
}
private static ICollection<Element> ReduceRows(ICollection<RowElement> elements, float availableWidth)
{
var constantWidth = elements
.Where(x => x is ConstantRowElement)
.Cast<ConstantRowElement>()
.Sum(x => x.Width);
var relativeWidth = elements
.Where(x => x is RelativeRowElement)
.Cast<RelativeRowElement>()
.Sum(x => x.Width);
var widthPerRelativeUnit = (availableWidth - constantWidth) / relativeWidth;
return elements
.Select(x =>
{
if (x is RelativeRowElement r)
return new ConstantRowElement(r.Width * widthPerRelativeUnit)
{
Child = x.Child
};
return x;
})
.Select(x => new Constrained
{
MinWidth = x.Width,
MaxWidth = x.Width,
Child = x.Child
})
.Cast<Element>()
.ToList();
}
private static ICollection<RowElement> AddSpacing(ICollection<RowElement> elements, float spacing)
{
if (spacing < Size.Epsilon)
return elements;
return elements
.SelectMany(x => new[] { new ConstantRowElement(spacing), x })
.Skip(1)
.ToList();
}
private static Element BuildTree(Span<Element> elements)
{
if (elements.IsEmpty)
return Empty.Instance;
if (elements.Length == 1)
return elements[0];
var half = elements.Length / 2;
return new SimpleRow
{
Left = BuildTree(elements.Slice(0, half)),
Right = BuildTree(elements.Slice(half))
};
}
#endregion
}
}
-60
View File
@@ -1,60 +0,0 @@
using System;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Scale : ContainerElement
{
public float ScaleX { get; set; } = 1;
public float ScaleY { get; set; } = 1;
internal override ISpacePlan Measure(Size availableSpace)
{
var targetSpace = new Size(
Math.Abs(availableSpace.Width / ScaleX),
Math.Abs(availableSpace.Height / ScaleY));
var measure = base.Measure(targetSpace) as Size;
if (measure == null)
return new Wrap();
var targetSize = new Size(
Math.Abs(measure.Width * ScaleX),
Math.Abs(measure.Height * ScaleY));
if (measure is PartialRender)
return new PartialRender(targetSize);
if (measure is FullRender)
return new FullRender(targetSize);
throw new ArgumentException();
}
internal override void Draw(Size availableSpace)
{
var skiaCanvas = (Canvas as Drawing.SkiaCanvasBase)?.Canvas;
if (skiaCanvas == null)
return;
var targetSpace = new Size(
Math.Abs(availableSpace.Width / ScaleX),
Math.Abs(availableSpace.Height / ScaleY));
var currentMatrix = skiaCanvas.TotalMatrix;
if (ScaleX < 0)
skiaCanvas.Translate(availableSpace.Width, 0);
if (ScaleY < 0)
skiaCanvas.Translate(0, availableSpace.Height);
skiaCanvas.Scale(ScaleX, ScaleY);
Child?.Draw(targetSpace);
skiaCanvas.SetMatrix(currentMatrix);
}
}
}
-18
View File
@@ -1,18 +0,0 @@
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class ShowEntire : ContainerElement
{
internal override ISpacePlan Measure(Size availableSpace)
{
var childMeasurement = Child?.Measure(availableSpace) ?? new FullRender(Size.Zero);
if (childMeasurement is FullRender)
return childMeasurement;
return new Wrap();
}
}
}
-140
View File
@@ -1,140 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
using IComponent = QuestPDF.Infrastructure.IComponent;
using IContainer = QuestPDF.Infrastructure.IContainer;
namespace QuestPDF.Elements
{
internal class SimpleStack : Element, IStateResettable
{
internal Element First { get; set; } = Empty.Instance;
internal Element Second { get; set; } = Empty.Instance;
internal bool IsFirstRendered { get; set; } = false;
internal override void HandleVisitor(Action<Element?> visit)
{
First?.HandleVisitor(visit);
Second?.HandleVisitor(visit);
base.HandleVisitor(visit);
}
public void ResetState()
{
IsFirstRendered = false;
}
internal override ISpacePlan Measure(Size availableSpace)
{
var firstElement = IsFirstRendered ? Empty.Instance : First;
var firstSize = firstElement.Measure(availableSpace) as Size;
if (firstSize == null)
return new Wrap();
if (firstSize is PartialRender partialRender)
return partialRender;
var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstSize.Height);
var secondSize = Second.Measure(spaceForSecond) as Size;
if (secondSize == null)
return new PartialRender(firstSize);
var totalWidth = Math.Max(firstSize.Width, secondSize.Width);
var totalHeight = firstSize.Height + secondSize.Height;
var targetSize = new Size(totalWidth, totalHeight);
if (secondSize is PartialRender)
return new PartialRender(targetSize);
return new FullRender(targetSize);
}
internal override void Draw(Size availableSpace)
{
var firstElement = IsFirstRendered ? Empty.Instance : First;
var firstMeasurement = firstElement.Measure(availableSpace);
if (firstMeasurement is FullRender)
IsFirstRendered = true;
var firstSize = firstMeasurement as Size;
if (firstSize != null)
firstElement.Draw(new Size(availableSpace.Width, firstSize.Height));
if (firstMeasurement is Wrap || firstMeasurement is PartialRender)
return;
var firstHeight = firstSize?.Height ?? 0;
var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstHeight);
var secondMeasurement = Second?.Measure(spaceForSecond) as Size;
if (secondMeasurement == null)
return;
Canvas.Translate(new Position(0, firstHeight));
Second.Draw(new Size(availableSpace.Width, secondMeasurement.Height));
Canvas.Translate(new Position(0, -firstHeight));
if (secondMeasurement is FullRender)
IsFirstRendered = false;
}
}
internal class Stack : IComponent
{
public ICollection<Element> Children { get; internal set; } = new List<Element>();
public float Spacing { get; set; } = 0;
public void Compose(IContainer container)
{
var elements = AddSpacing(Spacing, Children);
container
.PaddingBottom(-Spacing)
.Element(BuildTree(elements.ToArray()));
}
static ICollection<Element> AddSpacing(float spacing, ICollection<Element> elements)
{
if (spacing < Size.Epsilon)
return elements;
return elements
.Where(x => !(x is Empty))
.Select(x => new Padding
{
Bottom = spacing,
Child = x
})
.Cast<Element>()
.ToList();
}
static Element BuildTree(Span<Element> elements)
{
if (elements.IsEmpty)
return Empty.Instance;
if (elements.Length == 1)
return elements[0];
var half = elements.Length / 2;
return new SimpleStack
{
First = BuildTree(elements.Slice(0, half)),
Second = BuildTree(elements.Slice(half))
};
}
}
}
-117
View File
@@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Drawing;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using Size = QuestPDF.Infrastructure.Size;
namespace QuestPDF.Elements
{
internal class Text : Element
{
public string? Value { get; set; }
public TextStyle? Style { get; set; } = new TextStyle();
private float LineHeight => Style.Size * Style.LineHeight;
internal override ISpacePlan Measure(Size availableSpace)
{
var lines = BreakLines(availableSpace.Width);
var realWidth = lines
.Select(line => Style.BreakText(line, availableSpace.Width).FragmentWidth)
.DefaultIfEmpty(0)
.Max();
var realHeight = lines.Count * LineHeight;
if (realHeight > availableSpace.Height + Size.Epsilon)
return new Wrap();
return new FullRender(realWidth, realHeight);
}
internal override void Draw(Size availableSpace)
{
var lines = BreakLines(availableSpace.Width);
var offsetTop = 0f;
var offsetLeft = GetLeftOffset();
Canvas.Translate(new Position(0, Style.Size));
foreach (var line in lines)
{
Canvas.DrawText(line, new Position(offsetLeft, offsetTop), Style);
offsetTop += LineHeight;
}
Canvas.Translate(new Position(0, -Style.Size));
float GetLeftOffset()
{
return Style.Alignment switch
{
HorizontalAlignment.Left => 0,
HorizontalAlignment.Center => availableSpace.Width / 2,
HorizontalAlignment.Right => availableSpace.Width,
_ => throw new NotSupportedException()
};
}
}
#region Word Wrap
private List<string> BreakLines(float maxWidth)
{
var lines = new List<string> ();
var remainingText = Value.Trim();
while(true)
{
if (string.IsNullOrEmpty(remainingText))
break;
var breakPoint = BreakLinePoint(remainingText, maxWidth);
if (breakPoint == 0)
break;
var lastLine = remainingText.Substring(0, breakPoint).Trim();
lines.Add(lastLine);
remainingText = remainingText.Substring(breakPoint).Trim();
}
return lines;
}
private int BreakLinePoint(string text, float width)
{
var index = 0;
var lengthBreak = Style.BreakText(text, width).LineIndex;
while (index <= text.Length)
{
var next = text.IndexOfAny (new [] { ' ', '\n' }, index);
if (next <= 0)
return index == 0 || lengthBreak == text.Length ? lengthBreak : index;
if (next > lengthBreak)
return index;
if (text[next] == '\n')
return next;
index = next + 1;
}
return index;
}
#endregion
}
}
-23
View File
@@ -1,23 +0,0 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class Translate : ContainerElement
{
public float TranslateX { get; set; } = 1;
public float TranslateY { get; set; } = 1;
internal override void Draw(Size availableSpace)
{
var skiaCanvas = (Canvas as Drawing.SkiaCanvasBase)?.Canvas;
if (skiaCanvas == null)
return;
skiaCanvas.Translate(TranslateX, TranslateY);
base.Draw(availableSpace);
skiaCanvas.Translate(-TranslateX, -TranslateY);
}
}
}
-33
View File
@@ -1,33 +0,0 @@
using QuestPDF.Elements;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public static class DebugExtensions
{
public static IContainer Debug(this IContainer parent, string text, string color)
{
var container = new Container();
parent.Component(new Debug
{
Child = container,
Text = text,
Color = color
});
return container;
}
public static IContainer Debug(this IContainer parent, string text)
{
return parent.Debug(text, Colors.Red.Medium);
}
public static IContainer Debug(this IContainer parent)
{
return parent.Debug(string.Empty, Colors.Red.Medium);
}
}
}
-48
View File
@@ -1,48 +0,0 @@
using System;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Fluent
{
public static class ImageExtensions
{
public static void Image(this IContainer parent, byte[] data, ImageScaling scaling = ImageScaling.FitWidth)
{
if (data == null)
return;
var image = SKImage.FromEncodedData(data);
var aspectRatio = image.Width / (float)image.Height;
var imageElement = new Image
{
InternalImage = image
};
if (scaling != ImageScaling.Resize)
parent = parent.AspectRatio(aspectRatio, Map(scaling));
parent.Element(imageElement);
static AspectRatioOption Map(ImageScaling scaling)
{
return scaling switch
{
ImageScaling.FitWidth => AspectRatioOption.FitWidth,
ImageScaling.FitHeight => AspectRatioOption.FitHeight,
ImageScaling.FitArea => AspectRatioOption.FitArea,
_ => throw new ArgumentOutOfRangeException()
};
}
}
public static void Image(this IContainer element, Func<Size, byte[]> imageSource)
{
element.Element(new DynamicImage
{
Source = imageSource
});
}
}
}
-97
View File
@@ -1,97 +0,0 @@
using System;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public class PageDescriptor
{
internal Page Page { get; } = new Page();
public void Size(PageSize pageSize)
{
Page.MinSize = pageSize;
Page.MaxSize = pageSize;
}
public void ContinuousSize(float width)
{
Page.MinSize = new PageSize(width, 0);
Page.MaxSize = new PageSize(width, Infrastructure.Size.Max.Height);
}
public void MarginLeft(float value)
{
Page.MarginLeft = value;
}
public void MarginRight(float value)
{
Page.MarginRight = value;
}
public void MarginTop(float value)
{
Page.MarginTop = value;
}
public void MarginBottom(float value)
{
Page.MarginBottom = value;
}
public void MarginVertical(float value)
{
MarginTop(value);
MarginBottom(value);
}
public void MarginHorizontal(float value)
{
MarginLeft(value);
MarginRight(value);
}
public void Margin(float value)
{
MarginVertical(value);
MarginHorizontal(value);
}
public IContainer Header()
{
var container = new Container();
Page.Header = container;
return container;
}
public IContainer Content()
{
var container = new Container();
Page.Content = container;
return container;
}
public IContainer Footer()
{
var container = new Container();
Page.Footer = container;
return container;
}
}
public static class PageExtensions
{
public static IDocumentContainer Page(this IDocumentContainer document, Action<PageDescriptor> handler)
{
var descriptor = new PageDescriptor();
handler(descriptor);
(document as DocumentContainer).Pages.Add(descriptor.Page);
return document;
}
}
}
-27
View File
@@ -1,27 +0,0 @@
using System;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public static class RotateExtensions
{
private static IContainer Rotate(this IContainer element, Action<Rotate> handler)
{
var scale = element as Rotate ?? new Rotate();
handler(scale);
return element.Element(scale);
}
public static IContainer RotateLeft(this IContainer element)
{
return element.Rotate(x => x.TurnCount--);
}
public static IContainer RotateRight(this IContainer element)
{
return element.Rotate(x => x.TurnCount++);
}
}
}
-44
View File
@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public class RowDescriptor
{
internal Row Row { get; } = new Row();
public void Spacing(float value)
{
Row.Spacing = value;
}
public IContainer ConstantColumn(float width)
{
var element = new ConstantRowElement(width);
Row.Children.Add(element);
return element;
}
public IContainer RelativeColumn(float width = 1)
{
var element = new RelativeRowElement(width);
Row.Children.Add(element);
return element;
}
}
public static class RowExtensions
{
public static void Row(this IContainer element, Action<RowDescriptor> handler)
{
var descriptor = new RowDescriptor();
handler(descriptor);
element.Element(descriptor.Row);
}
}
}
-35
View File
@@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public class StackDescriptor
{
internal Stack Stack { get; } = new Stack();
public void Spacing(float value)
{
Stack.Spacing = value;
}
public IContainer Item()
{
var container = new Container();
Stack.Children.Add(container);
return container;
}
}
public static class StackExtensions
{
public static void Stack(this IContainer element, Action<StackDescriptor> handler)
{
var descriptor = new StackDescriptor();
handler(descriptor);
element.Component(descriptor.Stack);
}
}
}
-124
View File
@@ -1,124 +0,0 @@
using System;
using QuestPDF.Infrastructure;
namespace QuestPDF.Fluent
{
public static class TextStyleExtensions
{
private static TextStyle Mutate(this TextStyle style, Action<TextStyle> handler)
{
style = style.Clone();
handler(style);
return style;
}
public static TextStyle Color(this TextStyle style, string value)
{
return style.Mutate(x => x.Color = value);
}
public static TextStyle FontType(this TextStyle style, string value)
{
return style.Mutate(x => x.FontType = value);
}
public static TextStyle Size(this TextStyle style, float value)
{
return style.Mutate(x => x.Size = value);
}
public static TextStyle LineHeight(this TextStyle style, float value)
{
return style.Mutate(x => x.LineHeight = value);
}
public static TextStyle Italic(this TextStyle style, bool value = true)
{
return style.Mutate(x => x.IsItalic = value);
}
#region Alignmnet
public static TextStyle Alignment(this TextStyle style, HorizontalAlignment value)
{
return style.Mutate(x => x.Alignment = value);
}
public static TextStyle AlignLeft(this TextStyle style)
{
return style.Alignment(HorizontalAlignment.Left);
}
public static TextStyle AlignCenter(this TextStyle style)
{
return style.Alignment(HorizontalAlignment.Center);
}
public static TextStyle AlignRight(this TextStyle style)
{
return style.Alignment(HorizontalAlignment.Right);
}
#endregion
#region Weight
public static TextStyle Weight(this TextStyle style, FontWeight weight)
{
return style.Mutate(x => x.FontWeight = weight);
}
public static TextStyle Thin(this TextStyle style)
{
return style.Weight(FontWeight.Thin);
}
public static TextStyle ExtraLight(this TextStyle style)
{
return style.Weight(FontWeight.ExtraLight);
}
public static TextStyle Light(this TextStyle style)
{
return style.Weight(FontWeight.Light);
}
public static TextStyle NormalWeight(this TextStyle style)
{
return style.Weight(FontWeight.Normal);
}
public static TextStyle Medium(this TextStyle style)
{
return style.Weight(FontWeight.Medium);
}
public static TextStyle SemiBold(this TextStyle style)
{
return style.Weight(FontWeight.SemiBold);
}
public static TextStyle Bold(this TextStyle style)
{
return style.Weight(FontWeight.Bold);
}
public static TextStyle ExtraBold(this TextStyle style)
{
return style.Weight(FontWeight.ExtraBold);
}
public static TextStyle Black(this TextStyle style)
{
return style.Weight(FontWeight.Black);
}
public static TextStyle ExtraBlack(this TextStyle style)
{
return style.Weight(FontWeight.ExtraBlack);
}
#endregion
}
}
-26
View File
@@ -1,26 +0,0 @@
using System;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
namespace QuestPDF.Infrastructure
{
internal abstract class Element : IElement
{
internal IPageContext PageContext { get; set; }
internal ICanvas Canvas { get; set; }
internal virtual void HandleVisitor(Action<Element?> visit)
{
visit(this);
}
internal void Initialize(IPageContext pageContext, ICanvas canvas)
{
PageContext = pageContext;
Canvas = canvas;
}
internal abstract ISpacePlan Measure(Size availableSpace);
internal abstract void Draw(Size availableSpace);
}
}
-18
View File
@@ -1,18 +0,0 @@
using System.Collections.Generic;
using SkiaSharp;
namespace QuestPDF.Infrastructure
{
internal interface ICanvas
{
void Translate(Position vector);
void DrawRectangle(Position vector, Size size, string color);
void DrawText(string text, Position position, TextStyle style);
void DrawImage(SKImage image, Position position, Size size);
void DrawExternalLink(string url, Size size);
void DrawLocationLink(string locationName, Size size);
void DrawLocation(string locationName);
}
}
-11
View File
@@ -1,11 +0,0 @@
using System.Collections.Generic;
namespace QuestPDF.Infrastructure
{
public interface IPageContext
{
void SetLocationPage(string key);
int GetLocationPage(string key);
ICollection<string> GetRegisteredLocations();
}
}
-45
View File
@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using QuestPDF.Elements;
namespace QuestPDF.Infrastructure
{
public class PageContext : IPageContext
{
public const string CurrentPageSlot = "currentPage";
public const string TotalPagesSlot = "totalPages";
private Dictionary<string, int> Locations { get; } = new Dictionary<string, int>();
private int PageNumber { get; set; }
internal void SetPageNumber(int number)
{
PageNumber = number;
Locations[CurrentPageSlot] = number;
if (!Locations.ContainsKey(TotalPagesSlot) || Locations[TotalPagesSlot] < number)
Locations[TotalPagesSlot] = number;
}
public void SetLocationPage(string key)
{
if (Locations.ContainsKey(key))
return;
Locations[key] = PageNumber;
}
public int GetLocationPage(string key)
{
if (!Locations.ContainsKey(key))
throw new ArgumentException($"The location '{key}' does not exists.");
return Locations[key];
}
public ICollection<string> GetRegisteredLocations()
{
return Locations.Keys;
}
}
}
-42
View File
@@ -1,42 +0,0 @@
namespace QuestPDF.Infrastructure
{
public class Size
{
public const float Epsilon = 0.001f;
public float Width { get; }
public float Height { get; }
public static Size Zero => new Size(0, 0);
public static Size Max => new Size(14_400, 14_400);
public Size(float width, float height)
{
Width = width;
Height = height;
}
public override string ToString() => $"(W: {Width}, H: {Height})";
protected bool Equals(Size other)
{
return Width.Equals(other.Width) && Height.Equals(other.Height);
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Size) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Width.GetHashCode() * 397) ^ Height.GetHashCode();
}
}
}
}
-24
View File
@@ -1,24 +0,0 @@
using QuestPDF.Helpers;
namespace QuestPDF.Infrastructure
{
public class TextStyle
{
internal string Color { get; set; } = Colors.Black;
internal string FontType { get; set; } = "Calibri";
internal float Size { get; set; } = 12;
internal float LineHeight { get; set; } = 1.2f;
internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
internal FontWeight FontWeight { get; set; } = FontWeight.Normal;
internal bool IsItalic { get; set; } = false;
public static TextStyle Default => new TextStyle();
public override string ToString()
{
return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}";
}
internal TextStyle Clone() => (TextStyle)MemberwiseClone();
}
}
-39
View File
@@ -1,39 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Authors>MarcinZiabek</Authors>
<Company>CodeFlint</Company>
<PackageId>QuestPDF</PackageId>
<Version>2021.5.2</Version>
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
<PackageReleaseNotes>New elements: Box, Grid, Canvas, EnsureSpance and Layers. Redesigned the Debug element. Added material design colors. Added list of basic fonts. Added spacing property to the Row element. Fluent API improvements and increased stability.</PackageReleaseNotes>
<LangVersion>8</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>QuestPDF contributors</Copyright>
<PackageTags>PDF file export generate create render portable document format quest free</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Nullable>enable</Nullable>
<TargetFrameworks>net462;netstandard2.0;netcoreapp2.0;netcoreapp3.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SkiaSharp" Version="2.80.2" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\ImagePlaceholder.png" />
<EmbeddedResource Include="Resources\Logo.png" />
<None Remove="ImagePlaceholder.png" />
<None Include="Resources\Logo.png">
<Pack>true</Pack>
<Visible>false</Visible>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>
-27
View File
@@ -1,27 +0,0 @@
## Rely on solid fundamentals
This library is created specifically for designing and arranging document layouts, with full paging support. Alternative solutions, such as HTML-based converters, are not designed for this purpose and therefore are often unpredictable and do not produce desired results.
## Work with organized self-explanatory code
The entire process of implementing PDF document, takes place in your code. Free yourself from slow visual designers and strange technological limitations. Follow simple yet highly effective approaches to create maintainable, high-quality code.
## Compose simple components into complex documents
Do you remember the feeling when your code just works? When your ideas are becoming real without any effort? Working with simple, easy to understand, self-explanatory and highly composable layout elements is the key here!
## Create and reuse components
Feel no fear of complex documents! Create custom, reusable components and divide the document's layout into easy to maintain pieces. Inject data to customize content and use slots to enhance composability. Decide how complex approaches your solution needs and follow the best path.
## Prototype with ease
We understand that document generation is often tricky and require multiple iterations. The library offers additional prototyping tools such as random text generator or image placeholder element. By following best practices, you can develop a document without having data.
## Enjoy fast PDF generation
QuestPDF is created upon SkiaSharp, a well-known graphical library, and converts your data into PDF documents. It offers a highly optimized layouting engine capable of generating over 1000 PDF files per minute per core. The entire process is thread-safe.
## Write less, achieve more
Do you believe that creating a complete invoice document can take less than 200 lines of code? We have prepared for you a step-by-step instruction that shows every detail of this implementation and describes the best patterns and practices. [Learn more](https://www.questpdf.com/documentation/getting-started.html)
+92
View File
@@ -0,0 +1,92 @@
<a href="https://www.questpdf.com/" target="_blank">
<img src="https://github.com/QuestPDF/example-invoice/raw/main/images/logo.svg" width="400">
</a>
---
[![QuestPDF Homepage](https://img.shields.io/badge/Homepage-blue?style=for-the-badge)](https://www.questpdf.com)
[![Dotnet](https://img.shields.io/badge/platform-.NET-blue?style=for-the-badge)](https://www.nuget.org/packages/QuestPDF/)
[![GitHub Repo stars](https://img.shields.io/github/stars/QuestPDF/QuestPDF?style=for-the-badge)](https://github.com/QuestPDF/QuestPDF/stargazers)
[![Nuget version](https://img.shields.io/nuget/v/QuestPdf?style=for-the-badge)](https://www.nuget.org/packages/QuestPDF/)
[![Nuget download](https://img.shields.io/nuget/dt/QuestPDF?style=for-the-badge)](https://www.nuget.org/packages/QuestPDF/)
[![License](https://img.shields.io/github/license/QuestPDF/QuestPDF?style=for-the-badge)](https://github.com/QuestPDF/QuestPDF/blob/main/LICENSE)
<br />
### QuestPDF is a modern open-source .NET library for PDF document generation. Offering comprehensive layout engine powered by concise and discoverable C# Fluent API.
<img src="https://github.com/QuestPDF/QuestPDF-Documentation/blob/main/docs/public/previewer/animation.gif?raw=true" width="100%">
<table>
<tr>
<td>👨‍💻</td>
<td>Design PDF documents using C# and employ a code-only approach. Utilize your version control system to its fullest potential.</td>
</tr>
<tr>
<td>🧱</td>
<td>Compose PDF document with a range of powerful and predictable structural elements, such as text, image, border, table, and many more.</td>
</tr>
<tr>
<td>⚙️</td>
<td>Utilize a comprehensive layout engine, specifically designed for PDF document generation and paging support.</td>
</tr>
<tr>
<td>📖</td>
<td>Write code using concise and easy-to-understand C# Fluent API. Utilize IntelliSense to quickly discover available options.</td>
</tr>
<tr>
<td>🔗</td>
<td>Don't be limited to any proprietary scripting language or format. Follow your experience and leverage all modern C# features.</td>
</tr>
<tr>
<td>⌛</td>
<td>Save time thanks to a hot-reload capability, allowing real-time PDF document preview without code recompilation.</td>
</tr>
</table>
<br />
<br />
## Please help by giving a star
Choosing a project dependency could be difficult. We need to ensure stability and maintainability of our projects. Surveys show that GitHub stars count play an important factor when assessing library quality.
⭐ Please give this repository a star. It takes seconds and help thousands of developers! ⭐
<img src="https://user-images.githubusercontent.com/9263853/224511996-9dd27a99-bef8-4d5e-bc14-9f6cfe0f5191.png" width="800" />
## Please share with the community
As an open-source project without funding, I cannot afford advertising QuestPDF in a typical way. Instead, the library relies on community interactions. Please consider sharing a post about QuestPDF and the value it provides. It really does help!
[![Share on Reddit](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit&style=for-the-badge)](https://reddit.com/submit?url=https://github.com/QuestPDF/QuestPDF&title=Check%20out%20QuestPDF%20%F0%9F%8E%8A%20a%20modern%20open-source%20.NET%20library%20%20for%20PDF%20document%20generation%20%F0%9F%9A%80)
[![Share on Twitter](https://img.shields.io/badge/share%20on-twitter-03A9F4?logo=twitter&style=for-the-badge)](https://twitter.com/share?url=https://github.com/QuestPDF/QuestPDF&text=Check%20out%20QuestPDF%20%F0%9F%8E%8A%20a%20modern%20open-source%20.NET%20library%20%20for%20PDF%20document%20generation%20%F0%9F%9A%80%20%23dotnet%20%23csharp%20%23questpdf)
[![Share on HackerNews](https://img.shields.io/badge/share%20on-hacker%20news-orange?logo=ycombinator&style=for-the-badge)](https://news.ycombinator.com/submitlink?u=https://github.com/QuestPDF/QuestPDF&t=QuestPDF%20-%20a%20modern%20open-source%20.NET%20library%20%20for%20PDF%20document%20generation)
[![Share on Facebook](https://img.shields.io/badge/share%20on-facebook-1976D2?logo=facebook&style=for-the-badge)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/QuestPDF/QuestPDF)
<br />
## Let's get started
Begin exploring the QuestPDF library today. You are 250 lines of C# code away from creating a fully functional PDF invoice implementation.
Read the Getting Started tutorial to familiarize yourself with general library architecture, important layout structures as well as to better understand helpful patterns and practices. Easily start designing your PDF documents, reports, invoices and even more.
[![Getting started tutorial](https://img.shields.io/badge/%F0%9F%9A%80%20read-getting%20started-blue?style=for-the-badge)](https://www.questpdf.com/getting-started.html)
<img src="https://github.com/QuestPDF/QuestPDF-Documentation/blob/main/docs/public/invoice-small.png?raw=true" width="400px">
<br />
## QuestPDF on JetBrains OSS Power-Ups
QuestPDF was presented on one of the episodes of OSS Power-Ups hosted by JetBrains. Huge thanks for Matthias Koch and entire JetBrains team for giving me a chance to show QuestPDF. You are the best!
<a href="https://www.youtube.com/watch?v=-iYvZvpLX0g">
<img src="https://github.com/QuestPDF/QuestPDF-Documentation/blob/main/docs/public/jetbrains-oss-powerups-youtube.png?raw=true" width="600px">
</a>
[![YouTube video about QuestPDF]( https://img.shields.io/badge/watch%20on-YouTube-red?logo=youtube&style=for-the-badge)](https://www.youtube.com/watch?v=-iYvZvpLX0g)
+14
View File
@@ -0,0 +1,14 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 2021.5.2 | :white_check_mark: |
| Older | :x: |
## Reporting a Vulnerability
Please report any code vulnerabilities using GitHub Issues. We are trying to respond within 1 day and analyze reported situation as soon as possible.
Please collaborate with us to find best solutation available.
Once the vulnerability is recognized and fixed, the issue is closed with appropraite message.
+131
View File
@@ -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,29 @@
using NUnit.Framework;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
namespace QuestPDF.Examples
{
public class AlignmentExamples
{
[Test]
public void Example()
{
RenderingTest
.Create()
.PageSize(400, 200)
.ProduceImages()
.ShowResults()
.Render(container =>
{
container
.Padding(25)
.Border(1)
.AlignBottom()
.Background(Colors.Grey.Lighten1)
.Text("Test");
});
}
}
}
@@ -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();
});
});
}
}
}
+88
View File
@@ -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,408 @@
using System;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Elements;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
public class ContentDirectionExamples
{
private Action<IContainer> ContentDirectionTemplate(Action<IContainer> content)
{
return container =>
{
container
.MinimalBox()
.ExtendHorizontal()
.Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn();
columns.ConstantColumn(1);
columns.RelativeColumn();
});
table.Header(header =>
{
header.Cell().ContentFromLeftToRight().Element(HeaderCell("Left-to-right"));
header.Cell().LineVertical(1).LineColor(Colors.Grey.Medium);
header.Cell().ContentFromRightToLeft().Element(HeaderCell("Right-to-left"));
static Action<IContainer> HeaderCell(string label)
{
return container => container
.BorderColor(Colors.Grey.Medium)
.Background(Colors.Grey.Lighten2)
.PaddingHorizontal(15)
.PaddingVertical(5)
.Text(label)
.FontSize(18)
.SemiBold();
}
});
table.Cell().Element(TestCell).ContentFromLeftToRight().Element(content);
table.Cell().LineVertical(1).LineColor(Colors.Grey.Medium);
table.Cell().Element(TestCell).ContentFromRightToLeft().Element(content);
static IContainer TestCell(IContainer container)
{
return container.Padding(15);
}
});
};
}
[Test]
public void Page()
{
RenderingTest
.Create()
.ProduceImages()
.ShowResults()
.EnableDebugging()
.RenderDocument(document =>
{
document.Page(page =>
{
page.Size(PageSizes.A5);
page.Margin(20);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontFamily("Calibri").FontSize(20));
page.ContentFromRightToLeft();
page.Content().Column(column =>
{
column.Spacing(20);
column.Item()
.Text("مثال على الفاتورة") // example invoice
.FontSize(32).FontColor(Colors.Blue.Darken2).SemiBold();
column.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn();
columns.ConstantColumn(75);
columns.ConstantColumn(100);
});
table.Cell().Element(HeaderStyle).Text("وصف السلعة"); // item description
table.Cell().Element(HeaderStyle).Text("كمية"); // quantity
table.Cell().Element(HeaderStyle).Text("سعر"); // price
var items = new[]
{
"دورة البرمجة", // programming course
"دورة تصميم الرسومات", // graphics design course
"تحليل وتصميم الخوارزميات", // analysis and design of algorithms
};
foreach (var item in items)
{
var price = Placeholders.Random.NextDouble() * 100;
table.Cell().Text(item);
table.Cell().Text(Placeholders.Random.Next(1, 10));
table.Cell().Text($"USD${price:F2}");
}
static IContainer HeaderStyle(IContainer x) => x.BorderBottom(1).PaddingVertical(5);
});
});
});
});
}
[Test]
public void Column()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Column(column =>
{
column.Spacing(5);
column.Item().Height(50).Width(50).Background(Colors.Red.Lighten1);
column.Item().Height(50).Width(100).Background(Colors.Green.Lighten1);
column.Item().Height(50).Width(150).Background(Colors.Blue.Lighten1);
});
}
}
[Test]
public void Row()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Row(row =>
{
row.Spacing(5);
row.AutoItem().Height(50).Width(50).Background(Colors.Red.Lighten1);
row.AutoItem().Height(50).Width(50).Background(Colors.Green.Lighten1);
row.AutoItem().Height(50).Width(75).Background(Colors.Blue.Lighten1);
});
}
}
[Test]
public void Table()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn();
columns.RelativeColumn();
columns.RelativeColumn();
});
table.Cell().Height(50).Background(Colors.Red.Lighten1);
table.Cell().Height(50).Background(Colors.Green.Lighten1);
table.Cell().Height(50).Background(Colors.Blue.Lighten1);
table.Cell().ColumnSpan(2).Height(50).Background(Colors.Orange.Lighten1);
});
}
}
[Test]
public void Constrained()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Width(50).Height(50).Background(Colors.Red.Lighten1);
}
}
[Test]
public void Unconstrained()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container
.Width(100)
.Height(100)
.Background(Colors.Grey.Lighten3)
.AlignCenter()
.AlignMiddle()
.Unconstrained()
.Width(50)
.Height(50)
.Background(Colors.Red.Lighten1);
}
}
[Test]
public void Inlined()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Column(column =>
{
column.Spacing(10);
column.Item().Text("Default alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(null));
column.Item().Text("Left alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(InlinedAlignment.Left));
column.Item().Text("Center alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(InlinedAlignment.Center));
column.Item().Text("Right alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(InlinedAlignment.Right));
});
static Action<IContainer> ContentWithAlignment(InlinedAlignment? alignment)
{
return container =>
{
container.Inlined(inlined =>
{
inlined.Spacing(5);
inlined.Alignment(alignment);
inlined.Item().Height(50).Width(50).Background(Colors.Red.Lighten1);
inlined.Item().Height(50).Width(75).Background(Colors.Green.Lighten1);
inlined.Item().Height(50).Width(100).Background(Colors.Blue.Lighten1);
inlined.Item().Height(50).Width(125).Background(Colors.Orange.Lighten1);
});
};
}
}
}
[Test]
public void Text()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Column(column =>
{
column.Spacing(10);
column.Item().Text("Default alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(null));
column.Item().Text("Left alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(HorizontalAlignment.Left));
column.Item().Text("Center alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(HorizontalAlignment.Center));
column.Item().Text("Right alignment").FontSize(14).SemiBold();
column.Item().Element(ContentWithAlignment(HorizontalAlignment.Right));
});
static Action<IContainer> ContentWithAlignment(HorizontalAlignment? alignment)
{
return container =>
{
container.Text(text =>
{
text.Alignment = alignment; // internal API
text.Span("Lorem ipsum").Bold().FontColor(Colors.Red.Medium);
text.Element().Width(5);
text.Span(Placeholders.LoremIpsum());
});
};
}
}
}
[Test]
public void Decoration()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Decoration(decoration =>
{
decoration.Before().Background(Colors.Green.Lighten1).Padding(5).Text("Before").FontSize(16);
decoration.Content().Background(Colors.Green.Lighten2).Padding(5).Text("Content").FontSize(16);
decoration.After().Background(Colors.Green.Lighten3).Padding(5).Text("After").FontSize(16);
});
}
}
[Test]
public void Dynamic()
{
RenderingTest
.Create()
.PageSize(PageSizes.A4)
.ProduceImages()
.ShowResults()
.EnableDebugging()
.Render(ContentDirectionTemplate(Content));
void Content(IContainer container)
{
container.Dynamic(new SimpleDynamic());
}
}
class SimpleDynamic : IDynamicComponent<int>
{
public int State { get; set; }
public DynamicComponentComposeResult Compose(DynamicContext context)
{
var content = context.CreateElement(container =>
{
container.Row(row =>
{
row.ConstantItem(50).Background(Colors.Red.Lighten2).Height(50);
row.ConstantItem(75).Background(Colors.Green.Lighten2).Height(50);
row.ConstantItem(100).Background(Colors.Blue.Lighten2).Height(50);
});
});
return new DynamicComponentComposeResult
{
Content = content,
HasMoreContent = false
};
}
}
}
}
+46
View File
@@ -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,55 @@
using System.Drawing;
using System.Globalization;
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.ToString(CultureInfo.InvariantCulture))
.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,186 @@
using System.Collections.Generic;
using System.Globalization;
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.Before().Element(header);
decoration.Content().Column(column =>
{
foreach (var row in rows)
column.Item().Element(row.Element);
});
decoration.After().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)
.DefaultTextStyle(TextStyle.Default.SemiBold())
.Row(row =>
{
row.ConstantItem(30).Text("#");
row.RelativeItem().Text("Item name");
row.ConstantItem(50).AlignRight().Text("Count");
row.ConstantItem(50).AlignRight().Text("Price");
row.ConstantItem(50).AlignRight().Text("Total");
});
});
}
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()
.DefaultTextStyle(TextStyle.Default.FontSize(14).SemiBold())
.Text($"Subtotal: {total}$");
});
}
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).ToString(CultureInfo.InvariantCulture));
row.RelativeItem().Text(item.ItemName);
row.ConstantItem(50).AlignRight().Text(item.Count.ToString(CultureInfo.InvariantCulture));
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
.Before()
.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,158 @@
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
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).ToString(CultureInfo.InvariantCulture));
table.Cell().Element(Style).Text(item.ItemName);
table.Cell().Element(Style).AlignRight().Text(item.Count.ToString(CultureInfo.InvariantCulture));
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));
});
});
}
}
}
@@ -1,4 +1,3 @@
using System;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Examples.Engine;
@@ -41,10 +40,12 @@ namespace QuestPDF.Examples
.Decoration(decoration =>
{
decoration
.Header()
.Before()
.Background(Colors.Grey.Medium)
.Padding(10)
.Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
.Text("Notes")
.FontSize(16)
.FontColor("#FFF");
decoration
.Content()
@@ -55,43 +56,7 @@ namespace QuestPDF.Examples
});
});
}
// [Test]
// public void Page()
// {
// RenderingTest
// .Create()
// .PageSize(298, 421)
// .Render(container =>
// {
// container
// .Background("#FFF")
// .Padding(15)
// .Page(page =>
// {
// page.Header()
// .Height(60)
// .Background(Colors.Grey.Lighten1)
// .AlignCenter()
// .AlignMiddle()
// .Text("Header");
//
// page.Content()
// .Background(Colors.Grey.Lighten2)
// .AlignCenter()
// .AlignMiddle()
// .Text("Content");
//
// page.Footer()
// .Height(30)
// .Background(Colors.Grey.Lighten1)
// .AlignCenter()
// .AlignMiddle()
// .Text("Footer");
// });
// });
// }
[Test]
public void Row()
{
@@ -103,27 +68,27 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(20)
.Stack(stack =>
.Column(column =>
{
stack.Item()
column.Item()
.PaddingBottom(10)
.AlignCenter()
.Text("This Row element is 700pt wide");
stack.Item().Row(row =>
column.Item().Row(row =>
{
row.ConstantColumn(100)
row.ConstantItem(100)
.Background(Colors.Grey.Lighten1)
.Padding(10)
.ExtendVertical()
.Text("This column is 100 pt wide");
row.RelativeColumn()
row.RelativeItem()
.Background(Colors.Grey.Lighten2)
.Padding(10)
.Text("This column takes 1/3 of the available space (200pt)");
row.RelativeColumn(2)
row.RelativeItem(2)
.Background(Colors.Grey.Lighten3)
.Padding(10)
.Text("This column takes 2/3 of the available space (400pt)");
@@ -146,15 +111,15 @@ namespace QuestPDF.Examples
.Row(row =>
{
row.Spacing(20);
row.RelativeColumn(2).Border(1).Background(Colors.Grey.Lighten1);
row.RelativeColumn(3).Border(1).Background(Colors.Grey.Lighten2);
row.RelativeColumn(4).Border(1).Background(Colors.Grey.Lighten3);
row.RelativeItem(2).Border(1).Background(Colors.Grey.Lighten1);
row.RelativeItem(3).Border(1).Background(Colors.Grey.Lighten2);
row.RelativeItem(4).Border(1).Background(Colors.Grey.Lighten3);
});
});
}
[Test]
public void Stack()
public void column()
{
RenderingTest
.Create()
@@ -164,13 +129,13 @@ namespace QuestPDF.Examples
container
.Background("#FFF")
.Padding(15)
.Stack(stack =>
.Column(column =>
{
stack.Spacing(15);
column.Spacing(15);
stack.Item().Background(Colors.Grey.Medium).Height(50);
stack.Item().Background(Colors.Grey.Lighten1).Height(100);
stack.Item().Background(Colors.Grey.Lighten2).Height(150);
column.Item().Background(Colors.Grey.Medium).Height(50);
column.Item().Background(Colors.Grey.Lighten1).Height(100);
column.Item().Background(Colors.Grey.Lighten2).Height(150);
});
});
}
@@ -185,7 +150,7 @@ namespace QuestPDF.Examples
{
container
.Padding(25)
.Debug("Grid example", Colors.Blue.Medium)
.DebugArea("Grid example", Colors.Blue.Medium)
.Grid(grid =>
{
grid.Columns(3);
@@ -304,12 +269,12 @@ namespace QuestPDF.Examples
layers
.PrimaryLayer()
.Padding(25)
.Stack(stack =>
.Column(column =>
{
stack.Spacing(5);
column.Spacing(5);
foreach (var _ in Enumerable.Range(0, 7))
stack.Item().Text(Placeholders.Sentence());
column.Item().Text(Placeholders.Sentence());
});
// layer above the main content
@@ -317,12 +282,15 @@ namespace QuestPDF.Examples
.Layer()
.AlignCenter()
.AlignMiddle()
.Text("Watermark", TextStyle.Default.Size(48).Bold().Color(Colors.Green.Lighten3));
.Text("Watermark")
.FontSize(48)
.Bold()
.FontColor(Colors.Green.Lighten3);
layers
.Layer()
.AlignBottom()
.PageNumber("Page {pdf:currentPage}", TextStyle.Default.Size(16).Color(Colors.Green.Medium));
.Text(text => text.CurrentPageNumber().FontSize(16).FontColor(Colors.Green.Medium));
});
});
}
@@ -341,16 +309,16 @@ namespace QuestPDF.Examples
// {
// page.Header().PageNumber("Page {pdf:currentPage}");
//
// page.Content().Height(300).Stack(content =>
// page.Content().Height(300).column(content =>
// {
// content.Item().Height(200).Background(Colors.Grey.Lighten2);
//
// content.Item().EnsureSpace(100).Stack(stack =>
// content.Item().EnsureSpace(100).column(column =>
// {
// stack.Spacing(10);
// column.Spacing(10);
//
// foreach (var _ in Enumerable.Range(0, 4))
// stack.Item().Height(50).Background(Colors.Green.Lighten1);
// column.Item().Height(50).Background(Colors.Green.Lighten1);
// });
// });
// });
@@ -415,7 +383,7 @@ namespace QuestPDF.Examples
.Row(row =>
{
foreach (var color in colors)
row.RelativeColumn().Background(color);
row.RelativeItem().Background(color);
});
});
}
@@ -453,7 +421,9 @@ namespace QuestPDF.Examples
.Border(1)
.BorderColor(Colors.Grey.Medium)
.Padding(10)
.Text(font, TextStyle.Default.FontType(font).Size(16));
.Text(font)
.FontFamily(font)
.FontSize(16);
}
});
});
@@ -474,10 +444,10 @@ namespace QuestPDF.Examples
{
layers.Layer().Text("Something else");
layers.PrimaryLayer().Stack(stack =>
layers.PrimaryLayer().Column(column =>
{
stack.Item().PaddingTop(20).Text("Text 1");
stack.Item().PaddingTop(40).Text("Text 2");
column.Item().PaddingTop(20).Text("Text 1");
column.Item().PaddingTop(40).Text("Text 2");
});
layers.Layer().Canvas((canvas, size) =>
@@ -493,7 +463,7 @@ namespace QuestPDF.Examples
});
layers.Layer().Background("#8F00").Extend();
layers.Layer().PaddingTop(40).Text("It works!", TextStyle.Default.Size(24));
layers.Layer().PaddingTop(40).Text("It works!").FontSize(24);
});
});
}
@@ -511,10 +481,10 @@ namespace QuestPDF.Examples
.Padding(15)
.Border(4)
.BorderColor(Colors.Blue.Medium)
//.Box()
//.MinimalBox()
.Background(Colors.Grey.Lighten2)
.Padding(15)
.Text("Test of the \n box element", TextStyle.Default.Size(20));
.Text("Test of the \n box element").FontSize(20);
});
}
@@ -523,21 +493,50 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
.PageSize(400, 400)
.PageSize(300, 175)
.Render(container =>
{
var style = TextStyle.Default.Size(20);
container
.Background("#FFF")
.Padding(25)
.Stack(stack =>
.Background(Colors.White)
.Padding(10)
.Decoration(decoration =>
{
stack.Spacing(5);
stack.Item().Background(Placeholders.BackgroundColor()).Scale(0.5f).Text("Smaller text", style);
stack.Item().Background(Placeholders.BackgroundColor()).Text("Normal text", style);
stack.Item().Background(Placeholders.BackgroundColor()).Scale(2f).Text("Bigger text", style);
stack.Item().Background(Placeholders.BackgroundColor()).Scale(-1.5f).Text("Flipped text", style);
var headerFontStyle = TextStyle
.Default
.Size(20)
.Color(Colors.Blue.Darken2)
.SemiBold();
decoration
.Before()
.PaddingBottom(10)
.Text("Example: scale component")
.Style(headerFontStyle);
decoration
.Content()
.Column(column =>
{
var scales = new[] { 0.8f, 0.9f, 1.1f, 1.2f };
foreach (var scale in scales)
{
var fontColor = scale <= 1f
? Colors.Red.Lighten4
: Colors.Green.Lighten4;
var fontStyle = TextStyle.Default.Size(16);
column
.Item()
.Border(1)
.Background(fontColor)
.Scale(scale)
.Padding(5)
.Text($"Content with {scale} scale.")
.Style(fontStyle);
}
});
});
});
}
@@ -547,31 +546,38 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
.PageSize(500, 300)
.PageSize(300, 200)
.Render(container =>
{
container
.Background("#FFF")
.MinimalBox()
.Padding(25)
.Box()
.Background(Colors.Green.Lighten4)
.Padding(5)
.Background(Colors.Green.Lighten3)
.TranslateX(15)
.TranslateY(15)
.Text("Text outside of bounds");
.Border(2)
.BorderColor(Colors.Green.Darken1)
.Padding(50)
.Text("Moved text")
.FontSize(25);
});
}
[Test]
public void Rotate()
public void ConstrainedRotate()
{
RenderingTest
.Create()
.PageSize(450, 450)
.PageSize(650, 450)
.Render(container =>
{
container
.Background("#FFF")
.Padding(20)
.Grid(grid =>
{
@@ -581,11 +587,10 @@ namespace QuestPDF.Examples
foreach (var turns in Enumerable.Range(0, 4))
{
grid.Item()
.Width(200)
.Width(300)
.Height(200)
.Background(Colors.Grey.Lighten3)
.Background(Colors.Grey.Lighten2)
.Padding(10)
//.Box()
.Element(element =>
{
foreach (var x in Enumerable.Range(0, turns))
@@ -593,24 +598,82 @@ namespace QuestPDF.Examples
return element;
})
.Box()
.Background(Colors.Grey.Lighten1)
.Text($"Rotated {turns * 90} degrees.", TextStyle.Default.Size(14));
.MinimalBox()
.Background(Colors.White)
.Padding(10)
.Text($"Rotated {turns * 90}°")
.FontSize(16);
}
});
});
}
[Test]
public void FreeRotate()
{
RenderingTest
.Create()
.PageSize(300, 300)
.Render(container =>
{
container
.Padding(25)
.Background(Colors.Grey.Lighten2)
.AlignCenter()
.AlignMiddle()
.Background(Colors.White)
.Rotate(30)
.Width(100)
.Height(100)
.Background(Colors.Blue.Medium);
});
}
[Test]
public void FreeRotateCenter()
{
RenderingTest
.Create()
.PageSize(300, 300)
.Render(container =>
{
container
.Padding(25)
.Background(Colors.Grey.Lighten2)
.AlignCenter()
.AlignMiddle()
.Background(Colors.White)
.TranslateX(50)
.TranslateY(50)
.Rotate(30)
.TranslateX(-50)
.TranslateY(-50)
.Width(100)
.Height(100)
.Background(Colors.Blue.Medium);
});
}
[Test]
public void Flip()
{
RenderingTest
.Create()
.PageSize(450, 450)
.PageSize(350, 350)
.Render(container =>
{
container
.Background("#FFF")
.Padding(20)
.Grid(grid =>
{
@@ -620,21 +683,25 @@ namespace QuestPDF.Examples
foreach (var turns in Enumerable.Range(0, 4))
{
grid.Item()
.Width(200)
.Height(200)
.Width(150)
.Height(150)
.Background(Colors.Grey.Lighten3)
.Padding(10)
.Element(element =>
{
if (turns == 1 || turns == 2)
element = element.FlipX();
element = element.FlipHorizontal();
if (turns == 2 || turns == 3)
element = element.FlipY();
element = element.FlipVertical();
return element;
})
.Text($"Flipped.", TextStyle.Default.Size(14));
.MinimalBox()
.Background(Colors.White)
.Padding(10)
.Text($"Flipped {turns}")
.FontSize(16);
}
});
});
@@ -649,17 +716,130 @@ namespace QuestPDF.Examples
.Render(container =>
{
container
.Padding(10)
.Border(2)
.Row(row =>
{
row.ConstantColumn(25)
row.ConstantItem(25)
.Border(1)
.RotateLeft()
.AlignCenter()
.AlignMiddle()
.Text("Sample text");
row.RelativeColumn().Border(1).Padding(5).Text(Placeholders.Paragraph());
row.RelativeItem().Border(1).Padding(5).Text(Placeholders.Paragraph());
});
});
}
[Test]
public void Unconstrained()
{
RenderingTest
.Create()
.PageSize(400, 350)
.Render(container =>
{
container
.Padding(25)
.PaddingLeft(50)
.Column(column =>
{
column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
column
.Item()
// creates an infinite space for its child
.Unconstrained()
// moves the child up and left
.TranslateX(-50)
.TranslateY(-50)
// limits the space for the child
.Width(100)
.Height(100)
.Background(Colors.Blue.Darken1);
column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
});
});
}
[Test]
public void ComplexLayout()
{
RenderingTest
.Create()
.PageSize(500, 225)
.Render(container =>
{
container
.Padding(25)
.Column(column =>
{
column.Item().Row(row =>
{
row.RelativeItem().LabelCell("Label 1");
row.RelativeItem(3).Grid(grid =>
{
grid.Columns(3);
grid.Item(2).LabelCell("Label 2");
grid.Item().LabelCell("Label 3");
grid.Item(2).ValueCell().Text("Value 2");
grid.Item().ValueCell().Text("Value 3");
});
});
column.Item().Row(row =>
{
row.RelativeItem().ValueCell().Text("Value 1");
row.RelativeItem(3).Grid(grid =>
{
grid.Columns(3);
grid.Item().LabelCell("Label 4");
grid.Item(2).LabelCell("Label 5");
grid.Item().ValueCell().Text("Value 4");
grid.Item(2).ValueCell().Text("Value 5");
});
});
column.Item().Row(row =>
{
row.RelativeItem().LabelCell("Label 6");
row.RelativeItem().ValueCell().Text("Value 6");
});
});
});
}
[Test]
public void DomainSpecificLanguage()
{
RenderingTest
.Create()
.PageSize(600, 310)
.Render(container =>
{
container
.Padding(25)
.Grid(grid =>
{
grid.Columns(10);
for(var i=1; i<=4; i++)
{
grid.Item(2).LabelCell(Placeholders.Label());
grid.Item(3).ValueCell().Image(Placeholders.Image(200, 150));
}
});
});
}
@@ -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);
}
}
}
}
@@ -0,0 +1,43 @@
using System;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples.Engine
{
public class SimpleDocument : IDocument
{
public const int ImageScalingFactor = 2;
private Action<IDocumentContainer> Content { get; }
private int MaxPages { get; }
private bool ApplyCaching { get; }
private bool ApplyDebugging { get; }
public SimpleDocument(Action<IDocumentContainer> content, int maxPages, bool applyCaching, bool applyDebugging)
{
Content = content;
MaxPages = maxPages;
ApplyCaching = applyCaching;
ApplyDebugging = applyDebugging;
}
public DocumentMetadata GetMetadata()
{
return new DocumentMetadata()
{
RasterDpi = PageSizes.PointsPerInch * ImageScalingFactor,
DocumentLayoutExceptionThreshold = MaxPages,
ApplyCaching = ApplyCaching,
ApplyDebugging = ApplyDebugging
};
}
public void Compose(IDocumentContainer container)
{
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);
});
}
}
}
@@ -12,35 +12,38 @@ 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
{
[Test]
public void Frame(IContainer container)
public void Frame()
{
RenderingTest
.Create()
.PageSize(550, 400)
.ShowResults()
.Render(container =>
{
container
.Background("#FFF")
.Padding(25)
.Stack(stack =>
.Column(column =>
{
for(var i=1; i<=4; i++)
for(var i = 1; i <= 4; i++)
{
stack.Item().Row(row =>
column.Item().Row(row =>
{
row.RelativeColumn(2).LabelCell().Text(Placeholders.Label());
row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph());
row.RelativeItem(2).LabelCell(Placeholders.Label());
row.RelativeItem(3).ValueCell().Text(Placeholders.Paragraph());
});
}
});
@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
namespace QuestPDF.Examples
{
public class ProcessRunningTime
{
public TimeSpan FluentTime { get; set; }
public TimeSpan GenerationTime { get; set; }
public float Size { get; set; }
}
public class GenerationBenchmark
{
public const int TestSize = 4096;
[Test]
public void BenchmarkAsync()
{
RunTest(() => Enumerable
.Range(0, TestSize)
.AsParallel() // difference
.Select(GenerateAndCollect)
.ToList());
}
[Test]
public void BenchmarkSync()
{
RunTest(() => Enumerable
.Range(0, TestSize)
.Select(GenerateAndCollect)
.ToList());
}
public void RunTest(Func<IEnumerable<ProcessRunningTime>> handler)
{
var totalFluentTime = TimeSpan.Zero;
var totalGenerationTime = TimeSpan.Zero;
var stopWatch = new Stopwatch();
stopWatch.Start();
var results = handler();
stopWatch.Stop();
foreach (var result in results)
{
totalFluentTime += result.FluentTime;
totalGenerationTime += result.GenerationTime;
}
Console.WriteLine($"Fluent: {totalFluentTime:g}");
Console.WriteLine($"Generation: {totalGenerationTime:g}");
Console.WriteLine($"Total: {stopWatch.Elapsed:g}");
}
static ProcessRunningTime GenerateAndCollect(int attemptNumber)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var container = new Container();
container
.Padding(10)
.MinimalBox()
.Border(1)
.Column(column =>
{
column.Item().Text($"Attempts {attemptNumber}");
const int numberOfRows = 100;
const int numberOfColumns = 10;
for (var y = 0; y < numberOfRows; y++)
{
column.Item().Row(row =>
{
for (var x = 0; x < numberOfColumns; x++)
{
row.RelativeItem()
.Background(Colors.Red.Lighten5)
.Padding(3)
.Background(Colors.Red.Lighten4)
.Padding(3)
.Background(Colors.Red.Lighten3)
.Padding(3)
.Background(Colors.Red.Lighten2)
.Padding(3)
.Background(Colors.Red.Lighten1)
.Padding(3)
.Background(Colors.Red.Medium)
.Padding(3)
.Background(Colors.Red.Darken1)
.Padding(3)
.Background(Colors.Red.Darken2)
.Padding(3)
.Background(Colors.Red.Darken3)
.Padding(3)
.Background(Colors.Red.Darken4)
.Height(3);
}
});
}
});
var fluentTime = stopwatch.Elapsed;
stopwatch.Reset();
stopwatch.Start();
var size = Document
.Create(x => x.Page(page => page.Content().Element(container)))
.GeneratePdf()
.Length;
var generationTime = stopwatch.Elapsed;
return new ProcessRunningTime
{
FluentTime = fluentTime,
GenerationTime = generationTime,
Size = size
};
}
}
}
+42
View File
@@ -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}");
});
});
}
}
}
+89
View File
@@ -0,0 +1,89 @@
using System;
using System.IO;
using System.Linq;
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 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 DynamicImage()
{
RenderingTest
.Create()
.PageSize(450, 350)
.ProducePdf()
.ShowResults()
.Render(page =>
{
page.Padding(25)
.Image(Placeholders.Image);
});
}
[Test]
public void Exception()
{
Assert.Throws<DocumentComposeException>(() =>
{
RenderingTest
.Create()
.PageSize(PageSizes.A2)
.ProducePdf()
.ShowResults()
.Render(page => page.Image("non_existent.png"));
});
}
[Test]
public void ImageResolutionScaling()
{
var image = Image.FromFile("large-image.jpg");
Document
.Create(document =>
{
document.Page(page =>
{
page.Size(210, 210);
page.Margin(50);
page.Content().Image(image);
});
})
.GeneratePdf($"test.pdf");
}
}
}
+161
View File
@@ -0,0 +1,161 @@
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());
}
}
[Test]
public void RepeatingInlinedInHeader_Test()
{
RenderingTest
.Create()
.ProduceImages()
.ShowResults()
.RenderDocument(document =>
{
document.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Inch);
page.PageColor(Colors.White);
page.Header()
.Inlined(inlined =>
{
inlined.Spacing(10);
foreach (var i in Enumerable.Range(5, 5))
inlined.Item().Width(i * 10).Height(20).Background(Colors.Red.Medium);
});
page.Content()
.PaddingVertical(20)
.Column(column =>
{
column.Spacing(25);
foreach (var i in Enumerable.Range(10, 20))
column.Item().Width(i * 10).Height(50).Background(Colors.Grey.Lighten2);
});
});
});
}
}
}
Binary file not shown.
+57
View File
@@ -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");
});
});
}
}
}
@@ -19,10 +19,12 @@ namespace QuestPDF.Examples
{
var url = "https://picsum.photos/300/200";
if(Greyscale)
if (Greyscale)
url += "?grayscale";
using var client = new WebClient();
client.Headers.Add("user-agent", "QuestPDF/1.0 Unit Testing");
var response = client.DownloadData(url);
container.Image(response);
}
@@ -36,12 +38,14 @@ namespace QuestPDF.Examples
RenderingTest
.Create()
.PageSize(350, 280)
.ProducePdf()
.ShowResults()
.Render(container =>
{
container
.Background("#FFF")
.Padding(25)
.Stack(column =>
.Column(column =>
{
column.Spacing(10);
@@ -57,4 +61,4 @@ namespace QuestPDF.Examples
});
}
}
}
}
@@ -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");
}
}
}
@@ -12,7 +12,8 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
.PageSize(200, 150)
.PageSize(300, 300)
.ShowResults()
.Render(container =>
{
container
@@ -48,7 +49,9 @@ namespace QuestPDF.Examples
.Background("FFF")
.Padding(5)
.Text("Sample text", TextStyle.Default.FontType("Segoe UI emoji").Alignment(HorizontalAlignment.Center));
.AlignCenter()
.Text("Sample text")
.FontFamily("Segoe UI emoji");
});
}
@@ -61,7 +64,7 @@ namespace QuestPDF.Examples
.Render(container =>
{
container
.Stack(column =>
.Column(column =>
{
column
.Item()
@@ -111,14 +114,14 @@ namespace QuestPDF.Examples
.Render(container =>
{
container
.Stack(column =>
.Column(column =>
{
column
.Item()
.Height(150)
.Row(row =>
{
row.RelativeColumn()
row.RelativeItem()
.Extend()
.Background("FFF")
@@ -126,7 +129,7 @@ namespace QuestPDF.Examples
.Width(50)
.Background("444");
row.RelativeColumn()
row.RelativeItem()
.Extend()
.Background("BBB")
@@ -140,7 +143,7 @@ namespace QuestPDF.Examples
.Height(150)
.Row(row =>
{
row.RelativeColumn()
row.RelativeItem()
.Extend()
.Background("BBB")
@@ -148,7 +151,7 @@ namespace QuestPDF.Examples
.Width(50)
.Background("444");
row.RelativeColumn()
row.RelativeItem()
.Extend()
.Background("BBB")
@@ -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);
});
});
});
}
}
}

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